解决 Unity 游戏中的 ANR 是一个系统化的过程
集成报告服务
诸如 Android vitals、Firebase Crashlytics 和 Backtrace(经过认证的 Unity 合作伙伴)之类的报告服务可以大规模地为你的游戏提供错误日志记录和分析。在开发周期的早期将报告服务 SDK 集成到你的游戏中。分析哪个报告服务最符合你的游戏需求和预算。
不同的报告服务捕获 ANR 的方式不同。包含第二个报告服务以增加获得有效数据以支持你修复 ANR 决策的机会。
集成报告 SDK 不会影响游戏性能或 APK 大小。
分析符号
分析你的报告服务的报告,并检查堆栈跟踪是否为人类可读格式。有关更多信息,请参阅 为 Unity 游戏符号化 Android 崩溃和 ANR。
如何检查符号构建 ID
如果报告系统显示缺少构建 ID,但构建符号仍然存在于构建机器存储中,则可以检查符号的构建 ID,然后将其上传到报告服务。否则,需要新的构建才能上传符号文件。
在 Windows 或 macOS 上
- 根据你的 脚本后端(参见**解决方案**:)导航到符号文件夹。
- 使用以下命令(在 Windows 上,使用 Cygwin 运行
readelf
实用程序) - Grep 使用是可选的,用于过滤文本输出
- 查找构建 ID
- 使用以下命令(在 Windows 上,使用 Cygwin 运行
readelf -n libil2cpp.so | grep 'Build ID'
Build ID: b42473fb7449e44e0182dd1f580c99bab0cd8a95
检查游戏代码
当堆栈跟踪显示 libil2cpp.so
库中的函数时,错误发生在 C# 代码中,该代码已 转换为 C++。libil2cpp.so
库不仅包含你的游戏代码,还包含插件和包。
C++ 文件名遵循在 Unity 项目中定义的程序集名称。否则,文件名具有默认的 Assembly-C# 名称。例如,图 3 显示了文件 Game.cpp
(蓝色突出显示)上的错误,这是在程序集定义文件中定义的名称。Logger
是 C# 脚本中的类名(红色突出显示),后跟函数名(绿色突出显示)。最后是 IL2CPP 转换器生成的完整名称(橙色突出显示)。
通过执行以下操作检查你的游戏代码
- 检查 C# 项目中是否有任何可疑代码。通常,C# 未处理的异常不会导致 ANR 或应用程序崩溃。即便如此,也要确保代码在不同情况下都能正常运行。检查代码是否使用了第三方引擎模块,并分析最近的版本是否引入了错误。此外,请检查你是否最近更新了 Unity,或者错误是否只发生在特定设备上。
- 将游戏导出为 Android Studio 项目。通过完全访问你游戏转换后的 C# 源代码,你可以找到导致 ANR 的函数。C++ 代码看起来与你的 C# 代码非常不同,代码转换很少出现问题。如果你确实发现了问题,请向 Unity 提交支持工单。
- 查看游戏源代码,并确保在 OnApplicationFocus() 和 OnApplicationPause() 回调中运行的任何逻辑都已适当地清理。
- Unity 引擎有一个超时来暂停其执行;这些回调上的工作量过大可能会导致 ANR。
- 向代码部分添加日志或面包屑以增强你的数据分析。
- 使用 Unity Profiler 来调查游戏的性能。分析你的应用程序也可以帮助识别可能导致 ANR 的瓶颈。
- 识别主线程上长时间 I/O 操作的一个好方法是使用 严格模式。
- 分析 Android Vitals 或其他报告服务的历史记录,并检查发生错误最多的游戏的发布版本。查看版本控制历史记录中的源代码,并比较不同版本之间的代码更改。如果你发现可疑之处,请分别尝试每个更改或潜在的修复。
- 检查 Google Play ANR 报告历史记录中接收最多 ANR 的设备和 Android 版本。如果设备或版本已过时,则如果这样做不会影响游戏的盈利能力,则可以安全地忽略它们。仔细研究数据,因为特定用户组将无法再玩你的游戏。有关更多信息,请参阅 分发控制面板。
- 查看游戏源代码,确保你没有调用任何可能导致问题的代码,例如,如果 finish 使用不当,可能会造成破坏。请参阅 Android 开发者指南 了解更多关于 Android 开发的信息。
- 在查看数据并将游戏构建导出到 Android Studio 后,你将处理 C 和 C++ 代码,因此你可以充分利用 Unity 标准解决方案之外的工具,例如 Android 内存分析器、Android CPU 分析器 和 perfetto。
Unity引擎代码
要确定ANR是否发生在Unity引擎端,请检查堆栈跟踪中是否有libUnity.so
或libMain.so
。如果找到它们,请执行以下步骤
- 首先,搜索社区渠道(Unity论坛,Unity讨论,Stack Overflow)。
- 如果找不到任何信息,提交错误报告以解决问题。提供符号化的堆栈跟踪,以便引擎工程师能够更好地理解和解决错误。
- 检查最新的Unity LTS版本是否对您的问题进行了改进。如果是,请升级您的游戏以使用该版本。(此解决方案可能仅适用于部分开发者。)
- 如果您的代码使用自定义的
Activity
而不是默认的Activity,请检查Java代码以确保Activity没有造成任何问题。
第三方SDK
- 检查所有第三方库是否已更新,并且最新版本的Android没有关于崩溃或ANR的报告。
- 访问Unity论坛查看是否有任何错误已在更高版本中解决,或者Unity或社区成员是否提供了解决方法。
- 查看Google Play ANR报告并确保Google尚未识别出该错误。Google了解一些ANR并正在积极努力修复它们。
系统库
系统库通常不在开发者的控制范围内,但它们并不代表很大比例的ANR。除了联系库开发者或添加日志以缩小问题范围之外,系统库ANR很难解决。
退出原因
ApplicationExitInfo
是用于理解ANR原因的Android API。如果您的游戏使用Unity 6或更高版本,您可以直接调用ApplicationExitInfo
。对于较旧的Unity版本,您需要实现您自己的插件以启用来自Unity的ApplicationExitInfo
调用。
Crashlytics也使用ApplicationExitInfo
;但是,您自己的实现可以让您更精细地控制,并使您能够包含更多相关信息。