Unity手游崩溃异常如何捕获 C#及JVM捕获
1. C#脚本异常捕获
C#脚本未捕获的异常与Android和Native未捕获异常有很大区别,C#脚本的未捕获异常不会导致应用闪退。因此,C#脚本异常的危害相对较小,但在游戏中更易存在。闪退问题能够及时被发现并修复,而C#脚本异常由于抛出时机不同,危害性也有所差异。例如,在Start、Awake等函数中抛出的异常,会导致Update、OnGUI无法正常运行,游戏可能出现无响应、图片缺失等情况;Update、OnGUI中的异常也必然会引起游戏逻辑及画面上的异常。
从测试角度来看,C#脚本未捕获的异常必须报告给开发者。
1.1 AppDomain.CurrentDomain.UnhandledException回调
这是几乎所有语言都会提供的一种机制,用于在发生未捕获异常时进行回调。在Unity的文档中,System.AppDomain并不存在。根据微软官网的解释,CurrentDomain可获取当前应用程序当前线程的应用域。
微软官网提到:“If the UnhandledException event is handled in the default application domain, it is raised there for any unhandled exception in any thread, no matter what application domain the thread started in.” 这意味着,如果在默认域中注册,任何线程中抛出的未捕获异常都会触发这个未处理异常函数。
然而,在游戏中尝试在其他线程抛出异常时,该异常并未被此处理函数捕获。在UI线程中,Unity官方提供的函数大多都有try..catch机制,因此很难出现未捕获的异常。例如,尝试通过以下代码抛出未捕获异常:
GameObject.SendMessage("NonExistentMethod");
GameObject.SendMessage捕获了这个异常,并打印出了异常信息。所以,UnhandledException在大多数情况下作用不大。
1.2 Application.RegisterLogCallback日志回调
根据日志的TAG可以大致判断,UnityEngine自身的接口在捕获异常后会调用Debug.LogError输出日志。因此,可以通过注册RegisterLogCallback来获取系统调用。
但在OnLogCallbackHandler中,不能调用Debug.Log和Debug.LogError这些API,调用将无效。Unity可能是为了避免不必要的无限递归,在该函数中禁用了Debug.Log。可以通过AndroidJavaClass调用Java代码来输出日志,这样就能顺利输出未捕获的异常信息。
2. Java未捕获异常
Android在Thread中提供了setUncaughtExceptionHandler和setDefaultUncaughtExceptionHandler。setUncaughtExceptionHandler仅对注册的线程起作用,而setDefaultUncaughtExceptionHandler对所有线程都有效。因此,若要监听JVM层抛出的未捕获异常,可直接注册DefaultUncaughtExceptionHandler。
默认的未捕获处理函数在接收到异常后,最终会杀死进程。若不杀死进程,可能会导致无响应的问题。在代码中添加上述检测程序后,即可输出相应的日志结果。
来源:腾讯 作者:一位叫minhua的男工程师