本页面提供了问题排查帮助,并解答了有关使用 Crashlytics 的常见问题。如果您找不到想要的内容或需要其他帮助,请与 Firebase 支持团队 联系。
常规问题排查/常见问题解答
没有看到疾速崩溃提醒
如果您没有看到疾速崩溃提醒,请确保您使用的是
没有看到“未遇到崩溃问题”指标(或看到不可靠的指标)
如果您没有看到“未遇到崩溃问题”指标(例如“未遇到崩溃问题”的用户数和“未遇到崩溃问题”的会话数)或看到不可靠的指标,请检查以下各项:
谁可以查看、撰写和删除问题的备注?
借助备注功能,项目成员可以就相关疑问或状态更新等特定问题进行备注。
项目成员发布备注时,系统会标注其 Google 账号所对应的邮箱。此电子邮件地址将与备注一起向有权访问备注的所有项目成员显示。
下文介绍了查看、撰写和删除备注所需的权限 :
什么是回归问题?
如果您之前修复并关闭了某个问题,但 Crashlytics 收到了一个该问题再次发生的新报告,则表明该问题已回归。Crashlytics 会自动重新打开这些回归问题,以便您可以根据自己的应用需求采取相应措施。
以下示例场景说明了 Crashlytics 如何将问题归类为回归问题:
Crashlytics 首次收到有关崩溃“A”的崩溃报告。Crashlytics 会为该崩溃打开相应的问题(问题“A”)。
您快速修复此 bug,关闭问题“A”,然后发布应用的新版本。
在您关闭问题后,Crashlytics 收到关于问题“A”的另一份报告。
如果报告来自 Crashlytics 在您关闭问题时知道的应用版本(这意味着该版本已针对任何崩溃发送了崩溃报告),则 Crashlytics 不会将问题视为回归。 此问题将保持关闭状态。
如果报告来自 Crashlytics 在您关闭问题时不 知道的应用版本 (这意味着该版本从未针对任何崩溃发送过崩溃报告),则 Crashlytics 会将该问题视为回归问题,并将其重新打开。
注意 :在 2022 年 2 月之前,当任何应用版本(即使是我们在您关闭问题时知道的应用版本)中再次出现某个问题时,Crashlytics 就会将其归类为回归问题。 这导致了 Crashlytics 有时会错误地判定回归问题。现在,我们采用上述惯例。
当某个问题回归时,我们会发送回归检测提醒,并向该问题添加回归信号,让您知道 Crashlytics 已经重新打开了问题。如果您不希望由于回归算法而重新打开问题,请将该问题“静音”,而不是将其关闭。
为什么我看到旧版应用的回归问题?
如果报告来自在您关闭问题时从未发送过任何崩溃报告的旧应用版本,则 Crashlytics 会认为问题已回归,并会重新打开问题。
在以下情况下,可能会出现这种情形:您已修复了一个 bug,并发布了应用的新版本,但仍有一些用户在使用尚未包含该修复的旧版本。如果在您关闭问题时,碰巧其中一个旧版本从未发送过任何崩溃报告,而这些用户后来开始遇到 bug,那么这些崩溃报告将触发回归问题。
如果您不希望由于回归算法而重新打开问题,请将该问题“静音”,而不是将其关闭。
注意 :在 2022 年 2 月之前,当任何应用版本(即使是我们在您关闭问题时知道的应用版本)中再次出现某个问题时,Crashlytics 就会将其归类为回归问题。这导致了 Crashlytics 有时会错误地判定回归问题。现在,我们采用上述惯例。 如果您看到许多在 2022 年 2 月之前被误判的回归问题,可以再次将这些问题关闭,以免其被重新打开。
应用还使用了 Google Mobile Ads SDK,但无法收到崩溃信息
如果您的项目同时使用 Crashlytics 和 Google Mobile Ads SDK,这可能是由于在注册异常处理程序时,崩溃报告工具进行了干扰。如需解决此问题,请调用 disableSDKCrashReporting,在 Mobile Ads SDK 中关闭崩溃报告。
我的 BigQuery 数据集位于何处?
将 Crashlytics 关联到 BigQuery 后,无论您的 Firebase 项目位于何处,您创建的新数据集都会自动位于美国区域。
以下部分提供了针对特定平台的问题排查支持和常见问题解答:iOS+ |
Android |
Unity 。
dSYM 缺失/未上传
如需上传项目的 dSYM 并获取详细输出结果,请检查以下各项:
确保项目的 build 阶段包含 Crashlytics 运行脚本,该脚本允许 Xcode 在构建时上传项目的 dSYM(如需了解添加该脚本的说明,请参阅初始化 Crashlytics )。更新项目后,强制造成一次崩溃 并确认 Crashlytics 信息中心内显示此次崩溃。
如果您在 Firebase 控制台中看到“dSYM 缺失”提醒,请检查 Xcode,确保它针对构建正确生成了 dSYM 。
如果 Xcode 正确生成了 dSYM,但您仍看到 dSYM 缺失,这很可能是因为运行脚本工具在上传 dSYM 时卡住了。在这种情况下,请尝试以下各项操作:
请确保您使用的是最新版 Crashlytics 。
手动上传缺失的 dSYM 文件:
如果您仍然看到 dSYM 缺失或者上传仍然失败,请与 Firebase 支持团队 联系,并务必附上您的日志。
崩溃的符号化解析不正确
如果您的堆栈轨迹的符号化解析似乎不正确,请检查以下各项:
如果来自应用库的帧缺少对应用代码的引用,请确保未设置 -fomit-frame-pointer 编译标志。
如果您看到多个针对应用库的 (Missing) 帧,请检查 Firebase 控制台的“Crashlytics dSYMs”dSYMs 标签页 ,查看其中是否有可选的 dSYM 被列为缺失(针对受影响的应用版本)。如果是这样,请按照本页面上 dSYM 缺失/未上传常见问题解答 中的“dSYM 缺失提醒”问题排查步骤进行操作。请注意,上传这些 dSYM 并不会对已发生的崩溃进行符号化解析,但这有助于确保对今后的崩溃进行符号化解析。
为什么仅对 Android 11 及更高版本报告 ANR?
Crashlytics 支持对搭载 Android 11 及更高版本的设备中的 Android 应用报告 ANR。我们用于收集 ANR 的底层 API (getHistoricalProcessExitReasons ) 比基于 SIGQUIT 或基于监控定时器的方法更加可靠。此 API 仅适用于 Android 11 及更高版本的设备。
为什么有些 ANR 缺少 BuildId?
如果您的某些 ANR 缺少 BuildId,请按如下方式进行问题排查:
确保您使用的是最新版 Crashlytics Android SDK 和 Crashlytics Gradle 插件。
如果是在 Android 11 和某些 Android 12 ANR 中缺少 BuildId,则可能是因为您使用的 SDK 和/或 Gradle 插件已过时。如要正确收集这些 ANR 的 BuildId,您需要使用以下版本:
Crashlytics Android SDK 18.3.5 版及更高版本 (Firebase BoM v31.2.2+)
Crashlytics Gradle 插件 v2.9.4+
检查您的共享库是否使用了非标准位置。
如果只有应用的共享库缺少 BuildId,则可能是因为您的共享库没有使用标准的默认位置。在这种情况下,Crashlytics 可能无法找到关联的 BuildId。建议考虑让共享库使用标准位置。
确保您没有在构建流程中删除 BuildId。
请注意,以下问题排查提示对 ANR 和原生代码崩溃都适用。
通过对二进制文件运行 readelf -n 来检查 BuildId 是否存在。如果 BuildId 不存在,请将 -Wl,--build-id 添加到构建系统的标志中。
确保您没有因缩减 APK 大小而无意中删除 BuildId。
如果您同时保留了缩减版和完整版的库,请务必在代码中指向正确的版本。
Crashlytics 信息中心和 Google Play 管理中心的 ANR 报告之间的区别
Google Play 和 Crashlytics 中的 ANR 计数可能不一致。这在意料之中,因为两者的 ANR 数据收集和报告机制有所不同。Crashlytics 会在应用下次启动时报告 ANR,而 Android Vitals 会在发生 ANR 后即刻发送 ANR 数据。
此外,Crashlytics 仅显示搭载 Android 11 及更高版本的设备上发生的 ANR,而 Google Play 则显示使用 Google Play 服务且同意进行数据收集的设备上的 ANR。
为什么因 .kt 文件造成的崩溃被标为 .java 问题?
如果应用使用的是不显示文件扩展名的 obfuscator(混淆器),Crashlytics 会默认以 .java 文件扩展名生成问题。
为了让 Crashlytics 生成的问题带有正确的文件扩展名,请确保您的应用使用以下设置:
使用 Android Gradle 4.2.0 或更高版本
使用 R8 且启用混淆功能。如需将应用更新到 R8,请按照此文档 进行操作。
请注意,在更新到上述设置后,您可能会看到新的 .kt 问题,它们与现有的 .java 问题重复。请参阅常见问题解答 ,详细了解这种情况。
为什么 .kt 问题与现有的 .java 问题重复?
从 2021 年 12 月中旬开始,Crashlytics 改进了对使用 Kotlin 的应用的支持。
不久之前,可用的混淆器都不显示文件扩展名,因此 Crashlytics 默认以 .java 文件扩展名生成各个问题。不过,从 Android Gradle 4.2.0 开始,R8 支持文件扩展名。
经过此次更新,Crashlytics 现在可以确定应用中使用的每个类是否是以 Kotlin 编写的,并在问题签名中包含正确的文件名。如果您的应用采用以下设置,则崩溃现在可以正确归因于 .kt 文件(如果适用):
您的应用使用 Android Gradle 4.2.0 或更高版本。
您的应用使用 R8 且已启用混淆功能。
由于新崩溃的问题签名中现在包含正确的文件扩展名,因此您可能会看到新的 .kt 问题,而这些问题实际上与标记为 .java 的现有问题重复。在 Firebase 控制台中,我们会尝试识别新的 .kt 问题是否与标记为 .java 的现有问题重复,并通知您。
使用 DexGuard 时无法收到崩溃信息
如果您看到以下异常,可能是因为您使用的 DexGuard 版本与 Firebase Crashlytics SDK 不兼容:
java.lang.IllegalArgumentException: Transport backend 'cct' is not registered
此异常不会导致您的应用崩溃,但会阻止其发送崩溃报告。如需修复此问题,请执行以下操作:
确保您使用的是最新版 DexGuard 8.x。最新版本包含 Firebase Crashlytics SDK 所需的规则。
如果您不希望更改 DexGuard 版本,请尝试(在 DexGuard 配置文件中)向混淆规则添加以下内容:
- keepresourcexmlelements manifest / application / service / meta - data @value = cct
Crashlytics 信息中心和 Logcat 中的 NDK 堆栈轨迹之间的差异
LLVM 和 GNU 工具链针对您应用中的二进制文件只读段提供不同的默认值和处理方式,这可能会在 Firebase 控制台中生成不一致的堆栈轨迹。如需缓解此问题,请在构建流程中添加以下链接器标志:
如果堆栈轨迹仍不一致(或者两个标志都不适用于您的工具链),请试试将以下内容添加到构建流程:
-fno-omit-frame-pointer
如何将我自己的 Breakpad 符号文件生成器二进制程序用于 NDK?
Crashlytics 插件捆绑了一个定制的 Breakpad 符号文件生成器 。如果您希望使用自己的二进制程序来生成 Breakpad 符号文件(例如,如果您希望在自己的 build 链中从源代码构建所有原生可执行文件),请使用可选的 symbolGeneratorBinary 扩展属性来指定可执行文件的路径。
注意 :Android 二进制文件需要使用 Linux 版本的 Breakpad 符号文件生成器。 您可以通过以下方法指定 Breakpad 符号文件生成器二进制程序的路径:
方法 1 :在 build.gradle 文件中通过 firebaseCrashlytics 扩展指定路径
将以下内容添加到您的应用级 build.gradle.kts 文件:
Gradle 插件 v3.0.0+
android {
buildTypes {
release {
configure<CrashlyticsExtension> {
nativeSymbolUploadEnabled = true
// Add these optional fields to specify the path to the executable
symbolGeneratorType = "breakpad"
breakpadBinary = file ( "/PATH/TO/BREAKPAD/DUMP_SYMS " )
}
}
}
}
较低的插件版本
android {
// ...
buildTypes {
// ...
release {
// ...
firebaseCrashlytics {
// existing; required for either symbol file generator
nativeSymbolUploadEnabled true
// Add this optional new block to specify the path to the executable
symbolGenerator {
breakpad {
binary file ( "/PATH/TO/BREAKPAD/DUMP_SYMS " )
}
}
}
}
}
方法 2 :在 Gradle 属性文件中通过属性行指定路径
您可以使用 com.google.firebase.crashlytics.breakpadBinary 属性指定可执行文件的路径。
您可以手动更新 Gradle 属性文件,也可以通过命令行更新此文件。例如,如需通过命令行指定路径,请使用如下命令:
./gradlew -Pcom.google.firebase.crashlytics.symbolGenerator=breakpad \
-Pcom.google.firebase.crashlytics.breakpadBinary=/PATH/TO/BREAKPAD/DUMP_SYMS \
app:assembleRelease app:uploadCrashlyticsSymbolFileRelease
Crashlytics 是否支持 armeabi?
Firebase Crashlytics NDK 不支持 ARMv5 (armeabi)。从 NDK r17 开始,我们不再支持此 ABI。
在 Crashlytics 信息中心内看到未经过符号化解析的 Android 应用堆栈轨迹
如果您使用的是 Unity IL2CPP ,并且看到未经过符号化解析的堆栈轨迹,请尝试以下操作:
确保您使用的是 Crashlytics Unity SDK 8.6.1 或更高版本。
请确保您已设置并运行 Firebase CLI crashlytics:symbols:upload 命令,以生成和上传您的符号文件。
每当您创建发布 build 或者希望在 Firebase 控制台中查看符号化解析后的堆栈轨迹的任何 build 时,都需要运行此 CLI 命令。如需了解详情,请参阅获取易于理解的崩溃报告 。
Crashlytics 可以与使用 IL2CPP 的应用搭配使用吗?
可以,Crashlytics 支持为使用 IL2CPP 的应用提供经过符号化解析的堆栈轨迹。此功能适用于在 Android 或 Apple 平台上发布的应用。以下是您需要执行的操作:
确保您使用的是 Crashlytics Unity SDK 8.6.0 或更高版本。
完成适用于您的平台的必要任务:
对于 Apple 平台应用 :无需执行任何特殊操作。对于 Apple 平台应用,Firebase Unity Editor 插件将自动配置您的 Xcode 项目来上传符号。
对于 Android 应用 :请确保您已设置并运行 Firebase CLI crashlytics:symbols:upload 命令,以生成和上传您的符号文件。
每当您创建发布 build 或者希望在 Firebase 控制台中查看符号化解析后的堆栈轨迹的任何 build 时,都需要运行此 CLI 命令。如需了解详情,请参阅获取易于理解的崩溃报告 。
将未捕获的异常报告为严重异常
Crashlytics 可以将未捕获的异常报告为严重异常(从 Unity SDK v10.4.0 开始)。以下常见问题解答有助于说明使用此功能的理由和最佳做法。
为什么应用应将未捕获的异常报告为严重异常?
通过将未捕获的异常报告为严重异常,您可以更实际地了解哪些异常可能导致游戏无法玩,即使应用继续运行也是如此。
请注意,如果您开始报告严重异常,则未遇到崩溃问题的用户 (CFU) 比例可能会降低,但 CFU 指标更能代表最终用户的应用体验。
重要提示 :将未捕获的异常报告为严重异常 不会 影响您的 Android Vitals 。
Crashlytics 中报告的严重异常仅对您可见,以便您发现并解决应用和游戏中的问题。
哪些异常会报告为严重异常?
为了让 Crashlytics 将未捕获的异常报告为严重异常,必须同时满足以下两个条件:
在启用将未捕获的异常报告为严重异常后,我现在有许多新的严重异常。如何正确处理这些异常?
在您开始将未捕获的异常报告为严重异常时,可通过以下方法来处理这些未捕获的异常:
捕获和处理抛出的异常
系统会创建并抛出异常,以反映意外或异常状态 。若要解决抛出的异常所反映的问题,就需要将程序恢复到已知状态(此过程称为异常处理 )。
最佳实践是捕获并处理所有 预见的异常,除非程序无法恢复到已知状态。
如需控制由哪些代码捕获和处理哪些类型的异常,请将可能会生成异常的代码封装在 try-catch 块中 。请确保 catch 语句中的条件尽可能窄,以便适当地处理特定异常。
在 Unity 或 Crashlytics 中记录异常
您可以通过多种方式在 Unity 或 Crashlytics 中记录异常,以帮助调试问题。
在使用 Crashlytics 时,以下是两种最常见的推荐方法:
但是,如果您想手动将严重事件报告给 Unity Cloud Diagnostics,则可以使用 Debug.LogException。此方案会像方案 1 一样将异常输出到 Unity 控制台,但也会抛出异常(无论异常是被抛出还是被捕获)。 该方法会在非本地抛出错误。这意味着,即使周围的 Debug.LogException(exception) 包含 try-catch 代码块,仍会导致未捕获的异常。
因此,当且仅当您想要执行以下所有 操作时,才调用 Debug.LogException:
将异常输出到 Unity 控制台。
将异常作为严重事件上传到 Crashlytics 。
如需抛出异常,请将其视为 未捕获的异常,并将其报告给 Unity Cloud Diagnostics。
请注意,如果您要将捕获的异常输出到 Unity 控制台并 作为非严重事件上传到 Crashlytics ,请改为执行以下操作:
try
{
methodThatThrowsMyCustomExceptionType ();
}
catch ( MyCustomExceptionType exception )
{
// Print the exception to the Unity console at the error level.
Debug . LogError ( exception );
// Upload the exception to Crashlytics as a non-fatal event.
Crashlytics . LogException ( exception ); // not Debug.LogException
//
// Code that handles the exception
//
}