解决 Unity 游戏中的 ANR 问题是一个系统化的流程:
集成报告服务
Android Vitals (Android vitals)、Firebase Crashlytics 和 Backtrace(经过认证的 Unity 合作伙伴)等报告服务可大规模为您的游戏提供错误日志记录和分析功能。在开发周期的早期阶段,将报告服务 SDK 集成到游戏中。分析哪种报告服务最符合您的游戏需求和预算。
不同的报告服务捕获 ANR 的方式不同。添加第二个报告服务,以提高获取有效数据的机会,从而支持您在修复 ANR 时做出决策。
集成报告 SDK 不会影响游戏性能或 APK 大小。
分析符号
分析报告服务中的报告,并检查堆栈轨迹是否采用人类可读的格式。如需了解详情,请参阅对 Unity 游戏的 Android 崩溃和 ANR 问题进行符号化解析。
libil2cpp.so 符号。如何检查符号 build ID
如果报告系统显示缺失的 build ID,但 build 符号仍存在于 build 机器存储空间中,则可以检查符号的 build ID,然后将其上传到报告服务。否则,需要进行新的 build 才能上传符号文件。
在 Windows 或 macOS 上:
- 根据您的 脚本
后端 前往符号文件夹(请参阅 解决方案:)
- 使用以下命令(在 Windows 上,使用 Cygwin 运行
readelf实用程序) - grep 用法是可选的,用于过滤文本输出
- 查找 build 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 开发者指南 。
- 在检查数据并将游戏 build 导出到 Android Studio 后, 您将处理 C 和 C++ 代码,因此可以充分利用 Unity 标准解决方案之外的工具,例如 Android 内存分析器、Android CPU 性能分析器和 perfetto。
Unity 引擎代码
如需了解 ANR 是否发生在 Unity 引擎端,请检查堆栈轨迹中是否有 libUnity.so 或 libMain.so。如果找到它们,请执行以下步骤:
- 首先,搜索社区渠道(Unity 论坛、Unity 讨论、Stackoverflow)。
- 如果找不到任何内容,请提交 bug 以解决 问题。提供符号化堆栈轨迹,以便引擎工程师更好地了解和解决错误。
- 检查最新的 Unity LTS 是否针对您的问题进行了改进。如果是,请升级游戏以使用该版本。(此解决方案可能仅适用于部分开发者。)
- 如果您的代码使用自定义
Activity而不是默认值,请检查 Java 代码以确保 activity 不会导致任何问题。
第三方 SDK
- 检查所有第三方库是否都是最新版本,并且最新版本的 Android 是否没有关于崩溃或 ANR 的报告。
- 前往 Unity 论坛,查看是否有任何错误已在后续版本中得到解决,或者 Unity 或社区成员是否提供了解决方法。
- 检查 Google Play ANR 报告,确保 Google 尚未发现该错误。Google 已注意到一些 ANR,并且正在积极努力解决这些问题。
系统库
系统库通常远远超出开发者的控制范围,但它们在 ANR 中所占的比例并不高。除了与库开发者联系或添加日志以缩小问题范围之外,系统库 ANR 很难解决。
退出原因
ApplicationExitInfo 是一个 Android API,用于了解 ANR 原因。
如果您的游戏使用的是 Unity 6 或更高版本,您可以直接调用 ApplicationExitInfo
。对于旧版 Unity,您需要实现自己的插件,以启用来自 Unity 的 ApplicationExitInfo 调用。
Crashlytics 也使用 ApplicationExitInfo;不过,您自己的
实现可以提供更精细的控制,并让您能够添加
更多相关信息。