调试 ANR

解决 Unity 游戏中的 ANR 是一个系统性的过程:

图 1. 解决 Unity 游戏中 ANR 问题的步骤。

集成报告服务

报告服务,例如 Android VitalsFirebase CrashlyticsBacktrace(经过认证的 Unity) 合作伙伴)为您的游戏大规模提供错误日志记录和分析服务。集成 在开发周期的早期阶段将报告服务 SDK 添加到您的游戏中。分析 哪种报告服务最适合您的游戏需求和预算。

不同的报告服务捕获 ANR 的方法不同。添加 以便提高获取有效数据的几率 为您的决定如何解决 ANR 问题提供支持。

集成报告 SDK 不会影响游戏性能或 APK 大小。

分析符号

分析来自报告服务的报告并检查 堆栈轨迹是否采用人类可读的格式。请参阅对 Android 进行符号化解析 崩溃和 ANR

图 2. Crashlytics 显示 build ID 且缺少 libil2cpp.so 符号。

如何查看符号 build ID

如果报告系统显示缺少的 build ID,但 build 符号仍然显示 存在于构建机器存储空间中,则可以检查 然后将其上传到报告服务否则,系统会 上传符号文件所需的资源。

在 Windows 或 macOS 上:

  1. 根据您的脚本导航到符号文件夹 后端(请参阅解决方案:) <ph type="x-smartling-placeholder">
      </ph>
    1. 使用以下命令(在 Windows 上,使用 Cygwin 运行 readelf 实用程序)
    2. 可以选择使用 grep 来过滤文本输出
    3. 查找 build ID
readelf -n libil2cpp.so | grep 'Build ID'
Build ID: b42473fb7449e44e0182dd1f580c99bab0cd8a95

检查游戏代码

当堆栈轨迹显示 libil2cpp.so 库中的函数时, 错误发生在 C# 代码中,该代码已转换为 C++libil2cpp.so 库不仅包含您的游戏代码,还包含插件和软件包。

C++ 文件名遵循 Unity 项目中定义的汇编名称。 否则,文件名将采用默认的 Assembly-C# 名称。例如: 图 3 显示了 Game.cpp 文件(以蓝色突出显示)上的错误, 是在 Assembly Definition 文件中定义的名称。Logger 是 C# 脚本中的类名称(突出显示为红色),后跟 函数名称(以绿色突出显示)。最后是全名 IL2CPP 转换器生成的代码(以橙色突出显示)。

图 3. 测试来自 Backtrace 的项目调用堆栈。

执行以下操作,检查您的游戏代码:

  • 检查 C# 项目中是否存在任何可疑代码。通常,C# 未处理, 异常不会导致 ANR 或应用崩溃。即便如此,也要确保代码 在不同的情况下正常运行检查代码是否 使用第三方引擎模块,并分析 引发了错误。此外,还请检查 Unity 中,还是说该错误仅发生在特定设备上。
  • 将游戏导出为 Android Studio 项目。已完成 访问游戏转换后的 C# 源代码时,可以找到函数 哪些错误会导致 ANR。C++ 代码看起来与 C# 代码截然不同, 代码转换很少出现问题。如果您发现某些内容,请提交 Unity 的支持服务工单。
  • 查看游戏源代码,并确保在 OnApplicationFocus()OnApplicationPause() 适当清理回调
    • Unity 引擎设置了超时,以暂停其执行;工作负载过多 都可能会导致 ANR。
    • 向代码的各个部分添加日志或面包屑导航可增强数据分析。
  • 使用 Unity Profiler 调查游戏的 性能对应用进行性能分析也有助于确定 可能会导致 ANR 的瓶颈
  • 识别主线程上长时间运行的 I/O 操作的一个好方法是使用 严格模式
  • 分析 Android Vitals 或其他报告服务历史记录,并检查 出错最多的游戏的发布版本。评价 查看版本控制历史记录中的源代码,并比较代码更改 。如果发现可疑内容,请分别尝试每一种 更改或潜在修复方法。
  • 检查设备和 Android 的 Google Play ANR 报告历史记录 ANR 最多的版本如果设备或版本已过时 如果忽略它们不会影响游戏 盈利能力请仔细研究数据,因为只有特定用户群组 无法再玩您的游戏有关详情,请参阅分发 信息中心
  • 检查游戏源代码,确保您没有调用任何 都可能会导致问题,例如,finish 可能会 如果使用不当,则具有破坏性。请参阅 Android 开发者指南 来详细了解 Android 开发。
  • 查看数据并将游戏 build 导出到 Android Studio 后, 您可以使用 C 和 C++ 代码,因此可以充分利用各种工具 Unity 标准解决方案之外, Android 内存分析器Android CPU 性能分析器perfetto

Unity 引擎代码

如需了解 ANR 是否发生在 Unity 引擎端,请查看 堆栈轨迹中的 libUnity.solibMain.so。如果您找到了他们,请带 操作步骤:

  • 首先,搜索社区渠道(Unity 论坛Unity) 讨论Stackoverflow)。
  • 如果您没有找到任何内容,请提交 bug 以解决 问题。提供经过符号化解析的堆栈轨迹,以便引擎的工程师可以 以便更好地了解和解决错误。
  • 请查看最新版 Unity 版 LTS 针对您的问题做出了一些改进。如果是,请升级您的 使用该版本(此解决方案可能仅适用于 开发者。)
  • 如果您的代码使用自定义 Activity 而非默认值,请查看 Java 代码,用于确保 activity 不会导致任何问题。

第三方 SDK

  • 检查所有第三方库是否都是最新版本,且没有 最新版 Android 的崩溃或 ANR 问题。
  • 前往 Unity 论坛,查看是否已经出现任何错误 问题已解决,或者由 Unity 或社区成员。
  • 查看 Google Play ANR 报告,确保错误已 尚未被 Google 识别。Google 已经知道一些 ANR 问题 我们正积极努力解决这些问题

系统库

系统库通常离开发者的控制很远,但也不 所占的比例很大除了联系图书馆之外 或添加日志以缩小问题范围,系统库 ANR 很难解决。

退出原因

ApplicationExitInfo 是一个用于了解 ANR 原因的 Android API。 如果您的游戏使用的是 Unity 6 或更高版本,您可以调用 ApplicationExitInfo 。对于较低的 Unity 版本,您需要实现自己的插件 从 Unity 启用 ApplicationExitInfo 调用。

Crashlytics 还使用 ApplicationExitInfo;但您自己的 实施可让您进行更精细的控制, 更具相关性的信息