Crashlytics 问题排查和常见问题解答


本页面提供了问题排查帮助,并解答了有关使用 Crashlytics 的常见问题。如果您找不到想要的内容或需要其他帮助,请与 Firebase 支持团队联系。

常规问题排查/常见问题解答

您可能会注意到,Firebase 控制台的“问题”表格中列出的问题有两种不同的格式。您还有可能注意到,某些问题中具有一个称为“变体”的功能。原因如下:

2023 年初,我们发布了经过改进的事件分组分析引擎,还更新了设计,并推出了一些针对新问题的高级功能(例如变体)。如需了解详情,请参阅我们近期发布的博文;如需了解亮点,您可以阅读下文。

Crashlytics 会分析应用的所有事件(如崩溃、非严重错误和 ANR),并创建一种称为问题的事件组,以此将具有共同故障点的所有事件纳入一个问题。

为了将事件划分到这些问题中,经过改进的分析引擎现在会考虑事件的许多方面,包括堆栈轨迹中的帧、异常消息、错误代码以及其他平台或错误类型特征。

但在这种事件组中,导致各事件失败的堆栈轨迹可能有所不同。不同的堆栈轨迹可能代表着不同的根本原因。 为了体现一个问题内部可能存在的此类差异,我们现在会在问题内创建变体,变体是一个问题中的事件子组,该子组内的事件具有共同的故障点以及相似的堆栈轨迹。借助变体,您可以调试一个问题内最普遍的堆栈轨迹,并确定是否有不同的根本原因会导致这一故障。

改进后的体验如下:

  • 改进了问题行中显示的元数据
    现在,您可以更轻松地了解应用中的问题并进行分类。

  • 减少重复问题
    更改行号不会导致新问题。

  • 更轻松地调试存在多种不同根本原因的复杂问题
    使用变体调试一个问题中最普遍的堆栈轨迹。

  • 更有意义的提醒和信号
    新问题表示真的出现了新的 bug。

  • 更强大的搜索功能
    每个问题都包含更易于搜索的元数据,例如异常类型和软件包名称。

具体改进措施如下:

  • 从您的应用获取新事件时,我们会检查这些事件是否与现有问题匹配。

  • 如果没有匹配项,我们会自动为事件应用更智能的事件分组算法,并使用改进后的元数据设计创建新的问题。

这是我们对事件分组进行的第一次重大更新。如果您有任何反馈或遇到任何问题,请通过提交报告告诉我们。

如果您没有看到“未遇到崩溃问题”指标(例如未遇到崩溃问题的用户数和未发生崩溃问题的活跃日)和/或疾速崩溃提醒,请确保您使用的是 Crashlytics SDK 11.7.0+。

如果您没有看到路径日志,我们建议您检查应用的 Google Analytics 配置。请确保您符合以下要求:

如果您使用的是 Unity IL2CPP,并且看到未经过符号化解析的堆栈轨迹,请尝试以下操作:

  1. 确保您使用的是 Crashlytics Unity SDK 8.6.1 或更高版本。

  2. 请确保您已设置并运行 Firebase CLI crashlytics:symbols:upload 命令,以生成和上传您的符号文件。

    每当您创建发布 build 或者希望在 Firebase 控制台中查看符号化解析后的堆栈轨迹的任何 build 时,都需要运行此 CLI 命令。如需了解详情,请参阅获取易于用户理解的崩溃报告页面。

可以,Crashlytics 支持为使用 IL2CPP 的应用提供经过符号化解析的堆栈轨迹。此功能适用于在 Android 或 Apple 平台上发布的应用。以下是您需要执行的操作:

  1. 确保您使用的是 Crashlytics Unity SDK 8.6.0 或更高版本。

  2. 完成适用于您的平台的必要任务:

    • 对于 Apple 平台应用:无需执行任何特殊操作。对于 Apple 平台应用,Firebase Unity Editor 插件将自动配置您的 Xcode 项目来上传符号。

    • 对于 Android 应用:请确保您已设置并运行 Firebase CLI crashlytics:symbols:upload 命令,以生成和上传您的符号文件。

      每当您创建发布 build 或者希望在 Firebase 控制台中查看符号化解析后的堆栈轨迹的任何 build 时,都需要运行此 CLI 命令。如需了解详情,请参阅获取易于用户理解的崩溃报告页面。

“未遇到崩溃问题的用户”值表示与您的应用互动过,但在特定时间段内遇到崩溃问题的用户所占的百分比。

以下是计算未遇到崩溃问题的用户所占百分比的公式。其输入值由 Google Analytics 提供。

CRASH_FREE_USERS_PERCENTAGE = 1 - (CRASHED_USERS / ALL_USERS) x 100

  • 发生崩溃时,Google Analytics 会发送 app_exception 事件类型,CRASHED_USERS 表示与该事件类型关联的用户数量。

  • ALL_USERS 表示在您从 Crashlytics 信息中心右上角的下拉菜单中选择的时间段内与您的应用互动的用户总数。

未遇到崩溃问题的用户所占的百分比是一段时间内的汇总情况,而非平均值。

例如,假设您的应用有 3 位用户;我们将其称为用户 A、用户 B 和用户 C。下表显示了哪些用户每天与您的应用互动,以及其中哪些用户在当天发生了崩溃:

星期一 星期二 星期三
与您的应用互动过的用户 A、B、C A、B、C A、B
发生崩溃的用户 C B A
  • 在星期三,未遇到崩溃问题的用户所占百分比为 50%(1/2 的用户未遇到崩溃问题)。
    有 2 位用户在周三与您的应用互动过,但其中只有 1 位用户(用户 B)没有遇到崩溃问题。

  • 在过去 2 天内,未遇到崩溃问题的用户所占百分比为 33.3%(1/3 的用户未遇到崩溃问题)。
    3 位用户在过去 2 天内与您的应用互动过,但其中只有 1 位用户 (C) 未遇到崩溃问题。

  • 在过去 3 天内,未遇到崩溃问题的用户所占百分比为 0%(所有 3 个用户都遇到了崩溃问题)。
    3 位用户在过去 3 天内与您的应用进行了互动,但这 3 位用户都遇到了崩溃问题。

不应比较不同时间段的“未遇到崩溃问题的用户数”值。单个用户遇到崩溃问题的概率越高,其使用应用的次数越多,因此在较长的时间段内,未遇到崩溃问题的用户数的值可能会越小。

借助备注功能,项目成员可以就相关疑问或状态更新等特定问题进行备注。

项目成员发布备注时,系统会标注其 Google 账号的电子邮件地址。此电子邮件地址将与备注一起向有权访问备注的所有项目成员显示。

下文介绍了查看、撰写和删除备注所需的权限

请参阅了解“未遇到崩溃问题”指标

借助备注功能,项目成员可以就相关疑问或状态更新等特定问题进行备注。

项目成员发布备注时,系统会标注其 Google 账号的电子邮件地址。此电子邮件地址将与备注一起向有权访问备注的所有项目成员显示。

下文介绍了查看、撰写和删除备注所需的权限

集成

如果您的项目同时使用 CrashlyticsGoogle Mobile Ads SDK,这可能是由于在注册异常处理程序时,崩溃报告工具进行了干扰。如需解决此问题,请调用 disableSDKCrashReporting,在 Mobile Ads SDK 中关闭崩溃报告。

无论您的 Firebase 项目位于何处,将 Crashlytics 关联到 BigQuery 后,您创建的新数据集都会自动采用美国位置。

回归问题

如果您之前修复并关闭了某个问题,但 Crashlytics 收到了一个该问题再次发生的新报告,则表明该问题已回归。Crashlytics 会自动重新打开这些回归问题,以便您可以根据自己的应用需求采取相应措施。

以下示例场景说明了 Crashlytics 如何将问题归类为回归问题:

  1. Crashlytics 首次收到有关崩溃“A”的崩溃报告。Crashlytics 会为该崩溃打开相应的问题(问题“A”)。
  2. 您快速修复此 bug,关闭问题“A”,然后发布应用的新版本。
  3. 在您关闭问题后,Crashlytics 收到关于问题“A”的另一份报告。
    • 如果报告来自 Crashlytics 在您关闭问题时知道的应用版本(这意味着该版本已针对任何崩溃发送了崩溃报告),则 Crashlytics 不会将问题视为回归。此问题将保持关闭状态。
    • 如果报告来自 Crashlytics 在您关闭问题时知道的应用版本(这意味着该版本从未针对任何崩溃发送过崩溃报告),则 Crashlytics 会将该问题视为回归问题,并将其重新打开。

当某个问题回归时,我们会发送回归检测提醒,并向该问题添加回归信号,让您知道 Crashlytics 已经重新打开了问题。如果您不希望由于回归算法而要重新打开问题,请“忽略”问题,而不是将其关闭。

如果报告来自在您关闭问题时从未发送过任何崩溃报告的旧应用版本,则 Crashlytics 会认为问题已回归,并会重新打开问题。

在以下情况下,可能会出现这种情形:您已修复了一个 bug,并发布了应用的新版本,但仍有一些用户使用的是旧版本,而且未进行 bug 修复。如果偶然情况下,当您关闭问题时,其中一个旧版本根本没有发送过任何崩溃报告,并且这些用户开始遇到 bug,那么这些崩溃报告将触发回归问题。

如果您不希望由于回归算法而要重新打开问题,请“忽略”问题,而不是将其关闭。

将未捕获的异常报告为严重异常

Crashlytics 可以将未捕获的异常报告为严重异常(从 Unity SDK v10.4.0 开始)。以下常见问题解答有助于说明使用此功能的理由和最佳做法。

通过将未捕获的异常报告为严重异常,您可以更实际地了解哪些异常可能导致游戏无法玩,即使应用继续运行也是如此。

请注意,如果您开始报告严重异常,则未遇到崩溃问题的用户 (CFU) 比例可能会降低,但 CFU 指标更能代表最终用户的应用体验。

为了让 Crashlytics 将未捕获的异常报告为严重异常,必须同时满足以下两个条件:

在您开始将未捕获的异常报告为严重异常时,可通过以下方法来处理这些未捕获的异常:

捕获和处理抛出的异常

系统会创建并抛出异常,以反映意外或异常状态。若要解决抛出的异常所反映的问题,就需要将程序恢复到已知状态(此过程称为异常处理)。

最佳实践是捕获并处理所有预见的异常,除非程序无法恢复到已知状态。

如需控制由哪些代码捕获和处理哪些类型的异常,请将可能会生成异常的代码封装在 try-catch 块中。请确保 catch 语句中的条件尽可能窄,以便适当地处理特定异常。

在 Unity 或 Crashlytics 中记录异常

您可以通过多种方式在 Unity 或 Crashlytics 中记录异常,以帮助调试问题。

在使用 Crashlytics 时,以下是两种最常见的推荐方法:

  • 方法 1:在开发或问题排查期间,输出到 Unity 控制台,但不向 Crashlytics 报告

    • 使用将异常的内容输出到 Unity 控制台的 Debug.Log(exception)Debug.LogWarning(exception)Debug.LogError(exception) 输出到 Unity 控制台,且不会重新抛出异常。
  • 方法 2:对于以下情况,上传到 Crashlytics 以在 Crashlytics 信息中心内提供汇总报告:

    • 如果值得记录异常以调试可能的后续 Crashlytics 事件,请使用 Crashlytics.Log(exception.ToString())
    • 如果异常在捕获和处理后仍应报告给 Crashlytics,请使用 Crashlytics.LogException(exception) 将异常记录为非严重事件。

但是,如果您想手动将严重事件报告给 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
    //
}