分类存档: unity3d - 第2页

测试下unity中的异常在各平台上的表现

测试目的:

测试异常在android及ios64下的表现,查看是否导致闪退或崩溃。

测试代码:

	private void onclick1( ){
		Debug.Log("click1");
		int m=3;
		int n=0;
		Debug.Log(m/n);
	}
	private void onclick2( ){
		Debug.Log("click2");
		TestA test=null;
		Debug.Log(test.m);
	}

在unity editor中:

表现正常,没有导致app死掉。

在Android中:

可以在ddms中收集到异常,同时app没有崩溃。

在IOS中:

也是可以正常打出log及堆栈

发现也没有引起崩溃。

IOS上32位mono闪退的原因找到了:

解决方案:

http://developer.xamarin.com/guides/ios/troubleshooting/troubleshooting/

unity中计算使用的时间

基本上有几种方式

1、DateTime.UtcNow,性能好,速度快,但是精度低一此,10ms左右

2、第二种是用StopWatch,但是据称在多核多线程环境会有时有误差。

3、Process.GetCurrentProcess().TotalProcessorTime;时间准确度高,但相应的是性能较低下。可以使用宏定义,在测试版本中才开启,在正式发布版本中关闭这个功能。

噢,我们用时间,主要是用来埋点查看性能热点的地方。

fmod在ios64上无声音的问题

以前解决一个加载慢的问题时,发现fmod写的加载代码很差,尤其在android平台,做了很多无用功。

于是我就重写了fmod加载代码,使用www异步加载,加载的字节数组放在cache中,然后供fmod调用:

FMOD.RESULT result = FMOD_StudioSystem.sInstance.System.loadBankMemory(pair.Value,LOAD_BANK_FLAGS.NORMAL,out bank);

结果发现在ios上无法播放声音。

开始怀疑过il2cpp的问题,但是没有log,不能随便下定论。

添加过很多log后,定位到上面的函数出问题了,但是log中只记录执行到这里就没了。没有输出为什么错。

丝毫没有头绪后,在fmod官方发现有新版本了,下载新版本后,测试下,发现还是没有声音,但是至少有异常log了。

il2cpp暂时不支持从c/c++对c#进行调用,或者说至少不支持现在fmod的用法。

解决方法也很简单,修改为使用

	FMOD.RESULT result = FMOD_StudioSystem.instance.System.loadBankFile(bankPath, LOAD_BANK_FLAGS.NORMAL, out bank);

 

网上还有一个哥们遇到同样问题了,关注下看看他怎么解决。

http://forum.unity3d.com/threads/making-calls-from-c-to-c-with-il2cpp-instead-of-mono_runtime_invoke.295697/

 

看到一篇文件比较的unity下的各种调用的性能

http://forum.unity3d.com/threads/pinvoke-mono_add_internal_call-c-and-c.172886/

以备自己学习用。

这里还有一篇:http://www.snowbolt.com/index.php/blog/28-tech/91-pinvoke

目前看起来,mono要比c/c++慢一个数量级,lua又比mono慢一个数量级。

如果想要最好的性能,应该还是lua直接建在c/c++上,但是又如何去调用MonoBehaviour,如果能跳过mono,直接通过c/c++调用,则性能应该是最优的。但是需要确认下如何调用?

如果能实现,则是c/c++ + lua,直接跳过了 mono。

还有不确定的因素:il2cpp会不会可以直接实现这些性能提升?未来 需要确认下。

网上有位兄弟反编译的unity editor,看了下,不知道能否实现 lua 直接像调用c接口一样来调用MonoBehaviour.

namespace UnityEngine
{
    using System;
    using System.Collections;
    using System.Runtime.CompilerServices;

    public class MonoBehaviour : Behaviour
    {
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern MonoBehaviour();
        public void CancelInvoke()
        {
            this.Internal_CancelInvokeAll();
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void CancelInvoke(string methodName);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        private extern void Internal_CancelInvokeAll();
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        private extern bool Internal_IsInvokingAll();
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void Invoke(string methodName, float time);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void InvokeRepeating(string methodName, float time, float repeatRate);
        public bool IsInvoking()
        {
            return this.Internal_IsInvokingAll();
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern bool IsInvoking(string methodName);
        public static void print(object message)
        {
            Debug.Log(message);
        }

        public Coroutine StartCoroutine(IEnumerator routine)
        {
            return this.StartCoroutine_Auto(routine);
        }

        public Coroutine StartCoroutine(string methodName)
        {
            object obj2 = null;
            return this.StartCoroutine(methodName, obj2);
        }

        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern Coroutine StartCoroutine(string methodName, object value);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern Coroutine StartCoroutine_Auto(IEnumerator routine);
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void StopAllCoroutines();
        [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall]
        public extern void StopCoroutine(string methodName);

        public bool useGUILayout { [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] get; [MethodImpl(MethodImplOptions.InternalCall), WrapperlessIcall] set; }
    }
}

大计算量的代码,尽量避免使用c#代码,能用c/c++实现,就使用c/c++实现,然后暴露接口给c#层使用。

unity中的streaming文件路径

	IEnumerator test1(){
		String filePath1=Application.streamingAssetsPath+"/Boss.bank";
		String filePath2="file:///"+Application.streamingAssetsPath+"/Boss.bank";
		String filePath3=System.IO.Path.Combine(Application.streamingAssetsPath,"/Boss.bank");
		String filePath4=System.IO.Path.Combine(Application.streamingAssetsPath,"Boss.bank");


		textbox1.label.text=filePath1+"\n\n"+filePath2+"\n\n"+filePath3+"\n\n"+filePath4+"\n\n";

		textbox1.label.text+=File.Exists(filePath1)+"\n";
		textbox1.label.text+=File.Exists(filePath2)+"\n";
		textbox1.label.text+=File.Exists(filePath3)+"\n";
		textbox1.label.text+=File.Exists(filePath4)+"\n";

		WWW www1=new WWW(filePath1);
		yield return www1;

		WWW www2=new WWW(filePath2);
		yield return www2; 

		WWW www3=new WWW(filePath3);
		yield return www3;

		WWW www4=new WWW(filePath4);
		yield return www4;

		textbox1.label.text+=www1.bytesDownloaded+" "+www1.error+"\n";
		textbox1.label.text+=www2.bytesDownloaded+" "+www2.error+"\n";		
		textbox1.label.text+=www3.bytesDownloaded+" "+www3.error+"\n";		
		textbox1.label.text+=www4.bytesDownloaded+" "+www4.error+"\n";
	}

 

PC 运行如图:

android手机运行如图:

如果在unity中取文件:

string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "csv/"+configName);
		byte[] result=null;
		if (filePath.Contains("://")) {
			WWW www = new WWW(filePath);
			yield return www;
                        while(!www.isDone()){
                             yield return null;
                        }
			result = www.bytes;
		} else {
			result = System.IO.File.ReadAllBytes(filePath);
		}

如果在unity中想全部用www取文件

string filePath3 = Application.streamingAssetsPath + "/bt2/android/";
         if (!filePath3.Contains("://"))
         {
            filePath3 = "file:///" + filePath3;
         }

在android下需要注意,因为apk本身是压缩格式,无法直接用File取文件,必须用www取文件。

用www取文件注意格式,一定要等www.isDone

今天查找unity中加载配置表卡的问题(二)

接上一重篇:

http://blog.zhukunqian.com/?p=1234

上次修改完成后,配置加载已经非常快了, 但发现了另外一个现象,在检查配置更新时会卡上约6秒左右。

检查更新做的事情很简单,就是去网上请求一个静态文件,这里为什么卡成这样。

添加了一些埋点代码记录运行的时间后发现,卡在了加载音频那里,游戏中的音频有30M,而且那里是同步加载 -.-!! ,现在需要对音频进行拆分,

1、一部分需要在登陆前加载,比如UI上绑定的音频之类(按钮声)

2、一部分需要在战斗前加载成功,比如战斗中的音频

3、一部分需要异步加载,比如背景音乐之类

4、一部分只需要用时再加载,用完立即释放掉,比如人物对话音频之类。

另外在splash image后第一个场景需要update执行完后才会显示出来,因此有些非常耗时的操作避免在第一次update时执行。

今天查找unity中加载配置表卡的问题

我们游戏中第一次运行中,会下载配置表并进行加载。

但是我们发现一个现象:

第一次下载后,会在加载那里卡5秒左右。而以后再也不会遇到相同的卡的状况。

花了些时间发现了原因是c#代码导致的。

我们配置表使用csv,第一次下载后通过www类可以拿到下载的byte[],想避免一次IO操作,就使用c#写了解析为字符串数组的代码。

而非第一次下载,则使用File.ReadAllLine直接从文件中读取。

原来写时,以为能避免一次IO操作,可以提高性能,这里不能不说,C#自带的函数(底层使用c/c++实现),要远比c#的代码速度快的多。

也有可能是我写的C#代码太烂了的原因。

烂代码大家可以了解下:就是被注释掉的代码引导的卡。

string[] allDatas = null;

 	 	/*
        if (doneList != null)
        {
            for (int m = 0; m < doneList.Count; m++)
            {
                ConfigFile cf = doneList[m];
                if (cf.configName.Equals(configName+".bin"))
                {
					Debug.Log("Time1 :"+Time.realtimeSinceStartup);
                    StringReader sr = new StringReader(UTF8Encoding.UTF8.GetString(cf.content));
                    List<string> list = new List<string>();
                    string str = null;
                    while ((str = sr.ReadLine()) != null)
                    {
                        list.Add(str);
                    }
					Debug.Log("Time2:"+Time.realtimeSinceStartup);
                    allDatas = list.ToArray();
					Debug.Log("Time3:"+Time.realtimeSinceStartup+" "+configName+" "+list.Count);
                    break;
                }
            }
        }
        */
        if (allDatas == null)
        {
            string path = PathMgr.Config_Path + configName + ".bin";
            allDatas = File.ReadAllLines(path);
        }

unity EntryPointNotFoundException: getifaddrs

今天打包出现这个错误:

03-19 14:00:07.815: I/Unity(16574): EntryPointNotFoundException: getifaddrs
03-19 14:00:07.815: I/Unity(16574):   at (wrapper managed-to-native) System.Net.NetworkInformation.LinuxNetworkInterface:getifaddrs (intptr&)
03-19 14:00:07.815: I/Unity(16574):   at System.Net.NetworkInformation.LinuxNetworkInterface.ImplGetAllNetworkInterfaces () [0x00000] in <filename unknown>:0 
03-19 14:00:07.815: I/Unity(16574):   at System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces () [0x00000] in <filename unknown>:0 
03-19 14:00:07.815: I/Unity(16574): UnityEngine.GameObject:SendMessage(String, Object, SendMessageOptions)
03-19 14:00:07.815: I/Unity(16574): UICamera:Notify(GameObject, String, Object)
03-19 14:00:07.815: I/Unity(16574): UICamera:ProcessTouch(Boolean, Boolean)
03-19 14:00:07.815: I/Unity(16574): UICamera:ProcessTouches()
03-19 14:00:07.815: I/Unity(16574): UICamera:Update()

在网上搜索下:

Unfortunately this is a known bug in Mono for Android. The bug report is available here.

https://bugzilla.xamarin.com/show_bug.cgi?id=1969

是因为System.Net.NetworkInformation.GetAllNetworkInterfaces()在android上会报错导致的。

按power键返回,不出现锁屏,直接进入游戏

android 4.3.x 以上版本,不知道修改了哪里,按power键返回时,会导致游戏分辨率调整。

网上大多数做法是在onConfigurationChanged重新设置游戏的分辨率,这样会在切回来时,游戏可以调整为正确的分辨率。

 

mUnityPlayer.getView().getLayoutParams().width=mUnityPlayer._displayWidth;
mUnityPlayer.getView().getLayoutParams().height=mUnityPlayer._displayHeight;

这种做法基本上算是解决了问题。

实际上更好的方式是按power button后直接返回至游戏。发现unity的debug版本可以实现这个功能,有时间需要反编译下,看看代码差异在哪里。

 

unity 在游戏启动时按home键,再切回游戏黑屏

我们的游戏在启动时,如果切回后台,会几率性出现黑屏及资源加载错误。

我抓了一下android层的异常:

01-20 22:21:48.362: W/IInputConnectionWrapper(6525): showStatusIcon on inactive InputConnection
01-20 22:21:48.440: E/BufferQueue(190): [SurfaceView] connect: BufferQueue has been abandoned!
01-20 22:21:48.440: E/libEGL(6525): EGLNativeWindowType 0x76b53920 already connected to another API
01-20 22:21:48.440: E/libEGL(6525): eglCreateWindowSurface:525 error 3003 (EGL_BAD_ALLOC)
01-20 22:21:48.440: E/Unity(6525): [EGL] Failed to create surface
01-20 22:21:48.440: E/Unity(6525):  
01-20 22:21:48.440: E/Unity(6525): (Filename:  Line: 132)
01-20 22:21:48.440: E/Unity(6525): [EGL] Error:: EGL_BAD_ALLOC: EGL failed to allocate resources for the requested operation.
01-20 22:21:48.440: E/Unity(6525):  
01-20 22:21:48.440: E/Unity(6525): (Filename: ./PlatformDependent/AndroidPlayer/ContextGLES.cpp Line: 132)
01-20 22:21:48.441: E/libEGL(6525): call to OpenGL ES API with no current context (logged once per thread)

在网上搜索了很多文章,没有合适的解决方案。

在测试我们公司另一个项目的游戏时,发现他们没有这个问题,比较我们两个游戏,发现在启动速度上差别很大。

感觉这个问题的出现和启动慢有关系。查看启动部分代码,发现启动的类的field都是直接在类加载时进行的初始化。

感觉这里会阻塞线程,导致的unity初始时间非常长。

写了一个测试用例,分别在Awake(),Start()及类初始化时添加Thread.sleep(15000)的强制延迟。

发现Awake,Start不会阻塞unity的加载,会立即加载出splash image。在类初始化时,消耗大量时间,打出apk包,在手机上运行,也没有阻塞splash image显示。这下可真是奇怪了。

我先把我们游戏中在类加载时初始化的内容全转移至Awake中,再打个包测试下。

经过我们这边和珠海测试团队测试,进游戏时丢贴图的问题没有再次复现。是个好消息。

只剩下最后一个黑屏的问题,这个黑屏并不是BUG,只是客户端代码流程没有处理好。

——————————————————————————————

2015.01.22 更新:

本来以为黑屏是游戏中故意设置的黑屏,把游戏中的黑屏改为绿屏,结果发现黑屏问题依旧。

试着抓了一下异常:

01-22 13:36:59.538: E/XSJData(5438): serverId is null
01-22 13:36:59.675: E/XSJData(5438): serverId is null
01-22 13:38:07.740: E/linker(9195): load_library(linker.cpp:760): library "libmaliinstr.so" not found
01-22 13:38:07.744: E/(9195): appName=com.xsj.moon, acAppName=com.android.cts.openglperf
01-22 13:38:07.744: E/(9195): 0
01-22 13:38:07.744: E/(9195): appName=com.xsj.moon, acAppName=com.android.browser
01-22 13:38:07.744: E/(9195): 0
01-22 13:38:13.985: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/mscorlib.dll.so" not found
01-22 13:38:14.501: E/(9195): appName=com.xsj.moon, acAppName=com.android.cts.openglperf
01-22 13:38:14.501: E/(9195): 0
01-22 13:38:14.501: E/(9195): appName=com.xsj.moon, acAppName=com.android.browser
01-22 13:38:14.501: E/(9195): 0
01-22 13:38:14.714: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/UnityEngine.dll.so" not found
01-22 13:38:14.800: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/Assembly-CSharp-firstpass.dll.so" not found
01-22 13:38:14.902: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/Assembly-CSharp.dll.so" not found
01-22 13:38:14.906: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/Assembly-UnityScript.dll.so" not found
01-22 13:38:14.909: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/HOTween.dll.so" not found
01-22 13:38:14.913: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/JsonFx.Json.dll.so" not found
01-22 13:38:14.916: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/P31RestKit.dll.so" not found
01-22 13:38:14.918: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/Vectrosity.dll.so" not found
01-22 13:38:14.919: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/UMGameAnalyticsLibForAndroid.dll.so" not found
01-22 13:38:14.920: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/UMGameAnalyticsLibForiOS.dll.so" not found
01-22 13:38:17.802: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/System.Core.dll.so" not found
01-22 13:38:17.872: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/System.dll.so" not found
01-22 13:38:18.303: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/System.Xml.dll.so" not found
01-22 13:38:19.756: E/lsy(9195): UnityAwake
01-22 13:38:20.957: E/linker(9195): load_library(linker.cpp:760): library "/data/app/com.xsj.moon-1.apk/assets/bin/Data/Managed/System.dll.so" not found
01-22 13:38:24.040: E/linker(9195): load_library(linker.cpp:760): library "fmod" not found
01-22 13:38:24.048: E/linker(9195): load_library(linker.cpp:760): library "fmodstudio" not found
01-22 13:38:24.062: E/linker(9195): load_library(linker.cpp:760): library "fmodstudio" not found
01-22 13:38:26.182: E/linker(9195): load_library(linker.cpp:760): library "fmodstudio" not found
01-22 13:38:26.252: E/linker(9195): load_library(linker.cpp:760): library "fmodstudio" not found
01-22 13:38:26.255: E/linker(9195): load_library(linker.cpp:760): library "fmod" not found
01-22 13:38:26.738: E/XSJData(9195): serverId is null
01-22 13:38:26.868: E/XSJData(9195): serverId is null
01-22 13:38:28.460: E/WhetstoneSDK-JNI(9195): on Load native Whetstone

看起来还是程序中有BUG,并不是简单的逻辑异常。

unity中包中只存在对应的dll不存在对应的dll.so,这里应该是unity内部的加载机制被破坏掉了。

在goolge上搜索下unity加载dll的流程。

抓了一下正常流程的日志,在正常流程中也有上面的输出。看起来不是上面的原因。

—————————————————————————————————————-

2015.01.29

这几天为了这个花屏,黑屏的问题做了不了调查,现在基本上确认了点信息:

重现流程:

1、启动游戏

2、在splash image加载完成前,点home键返回主界面

3、点游戏图标进入游戏,出现黑屏。如果继续,则有可能出现花屏。

已经确认的信息:

1、我们的游戏中很多资源都放在的resources目录下,这会导致游戏加载很比较慢,这里可能会出现egl初始化未完成时,点home键返回界面,然后再点回来时,又创建了一次egl windows,而android中不允许同时存在两个egl windows,所以就会出现黑屏。

一条可能有用的信息:

01-29 15:23:12.572: W/MALI(3730): __egl_mali_post_to_window_surface:936: __egl_mali_post_to_window_surface: posting to window surface failed; couldn’t acquire output buffer (surface=0x7cb3b008)

还有另一条,从这里开始不停报错:

01-29 15:23:12.573: D/Unity(3730): [EGL] SwapBuffer: EGL_BAD_ALLOC: EGL failed to allocate resources for the requested operation.
01-29 15:23:12.933: E/Unity(3730): [EGL] Failed to create surface

参考:

http://stackoverflow.com/questions/15561780/createwindowsurface-failed-egl-bad-match

发现一件很奇怪的事,在小米手机上,如果安装完后直接启动游戏,则在游戏中按home键返回,再点游戏图标进入游戏,每次都会重新调用onCreate。

如果一开始使用游戏icon进入游戏,则不会有这个问题。

可能有用的一条log:

01-29 23:01:38.793: W/ManagedEGLContext(18120): doTerminate failed: EGL count is 2 but managed count is 1

黑屏的原因找到了,是因为4.3.1f1中unity每次pause后,eglcontext需要重建,但我们游戏中重建需要的时间太长,而且在重建完成前就是黑屏,而且这里还有另一个问题,如果在黑屏期再按pause返回,则会导致游戏中一个10秒的黑屏等待,如果你短时间内不停pause,则每一次puase导致的10秒等待会累加起来。

另参考:http://stackoverflow.com/questions/2112768/prevent-onpause-from-trashing-opengl-context

http://pastebin.com/U4x5JjAr

http://gamedev.stackexchange.com/questions/12629/workaround-to-losing-the-opengl-context-when-android-pauses

http://www.anddev.org/android-2d-3d-graphics-opengl-problems-f55/minimizing-opengl-texture-reloads-on-pause-resume-t52932.html

 

https://code.google.com/p/replicaisland/source/browse/trunk/src/com/replica/replicaisland/GLSurfaceView.java

——————————————————————————————————–

2015.02.03 不知道时间过去多长了,黑屏和花屏问题终于定位到了,项目代码中真是各种天坑。

先列下解决方案吧:

&lt;activity
            android:name="com.haifi.abc.MainActivity"
            android:configChanges="locale|mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
            android:label="@string/app_name"
            android:windowSoftInputMode="stateHidden"
            android:screenOrientation="sensorLandscape"
            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"&gt;
            &lt;intent-filter&gt;
                &lt;action android:name="android.intent.action.MAIN" /&gt;
                &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
            &lt;/intent-filter&gt;
        &lt;/activity&gt;
        &lt;activity android:label="@string/app_name" android:name="UnityPlayerActivityEx" android:screenOrientation="landscape" android:configChanges="locale|mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"&gt;
            <strong><span style="color: #ff0000;">&lt;meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" /&gt;</span></strong>
        &lt;/activity&gt;

1、使用unity中提供的默认UnityPlayerActivity,是从UnityPlayerNativeActivity继承而来,

http://docs.unity3d.com/Manual/PluginsForAndroid.html

这里有一段对UnityPlayerNativeActivity的描述,说明了unityplayer.ForwardnativeEventsToDalvik的作用,

我们项目中不知道是谁竟然删除了这些代码,unity默认生成的android工程中带着此代码的。

2、自己写一个类继承自UnityPlayerActivity,然后补充以下代码:

	protected void onCreate(Bundle paramBundle) {
		super.onCreate(paramBundle);
		if (Build.VERSION.SDK_INT >= 19) {
			getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(
					new View.OnSystemUiVisibilityChangeListener() {
						public void onSystemUiVisibilityChange(
								int paramAnonymousInt) {
							View localView = UnityPlayerActivityEx.this
									.getWindow().getDecorView();
							if ((paramAnonymousInt & 0x4) == 0) {
								localView.setSystemUiVisibility(5894);
							}
						}
					});
		}
	}

	public void onWindowFocusChanged(boolean paramBoolean) {
		super.onWindowFocusChanged(paramBoolean);
		if ((Build.VERSION.SDK_INT >= 14) && (paramBoolean)) {
			getWindow().setFlags(1024, 1024);
			getWindow().getDecorView().setSystemUiVisibility(6);
		}
		if ((Build.VERSION.SDK_INT >= 19) && (paramBoolean)) {
			getWindow().getDecorView().setSystemUiVisibility(5894);
		}
	}

OK,什么花屏和黑屏全都消失不见了。真是天坑。

另外这里还有进一步优化的余地:可以进一步阻止surfaceview的创建,这样按home键再返回,不会重建egl context。

 

——————————————————————————————————————–

2015.02.13记。这周又在处理这个问题,在MainActivity中添加代码后发现在第一次安装后直接在安装界面启动,按home键返回,再点游戏图标,就会直接黑屏。

这周怒了,把unity源码各个函数都添加日志,在android那一层把所有可能调用的函数都添加日志,意外发现MainActivity的onCreate被调用了两次???,不可理解,从理论上讲,MainActivity的onCreate永远只会被调用一次。

又添加测试代码,在MainActivity中设置一个private static int m=0;在onCreate中设置m++,然后输出m的值,发现果然,从启动界面启动游戏时,每次从home键返回都会调用onCreate,而且m的值一直在增加,说明这个进程并没有被结束。只是MainActivity被重复的创建。

我一开始想到的方法是既然MainActivity中多次创建,那根据m的值,只在第一次创建时,生成unityPlayer,其它的时间不再重新创建unityPlayer,这样可以避免unityPlayer被多次创建,就也自然避免的黑屏的问题。

但是这个方法一开始很好,但在测试中发现了问题,我们开始游戏时,会播放一个mp4视频,如果这时候按home返回,再返回游戏,又是黑屏,该死,这是因为我们的开发人员把播放视频放在了MainActivity中,而返回时,又因为onCreate的原因,又丢失掉了播放视频的view。

总之,走了NNNNNNN多的弯路。

到这里我又重新审视了自己的解决方法和问题根源,这里根源就是因为onCreate被调用了多次导致的,如果能解决这个问题,其它所有问题都是自然而解。

幸好老外早就遇到问题了,只是可惜我一开始没有走到正确的方向,导致花费了太多的时间。

好吧下面是一系列的奇遇:

1、我在google搜索: “android acitivity recreate from home button”

2、它建议我搜索: “android activity oncreate from home button”,好吧,同意它。

3、看到一个搜索结果:http://stackoverflow.com/questions/16981793/android-home-key-issue-at-first-time-calling-oncreate

4、果然是我需要的问题,里面建议去:http://code.google.com/p/android/issues/detail?id=2373

5、https://code.google.com/p/android/issues/detail?id=2373 好吧,果然是宝地,问题根源及解决方案(三种)都在里面。

这里我采用了,这个大师的解决方案。(当然,另外的解决方案也可以尝试)

<a href="https://github.com/cleverua/android_startup_activity" rel="nofollow">https://github.com/cleverua/android_startup_activity</a>

总结:也是自己太不了解android开发了,不然这个bug一看到就可以解决掉了。自己虽然花费很多精力,但中间解决问题的学习也让自己增长了不长见识。