الانتقال إلى وحدة التحكم

自定义您的 Firebase Crashlytics 崩溃报告

您只需要对 Firebase Crashlytics 进行极少量设置就可以让其工作。在您添加 SDK 后,Crashlytics 就会立即开始将崩溃报告发送到 Firebase 控制台

为了让您更深入地了解崩溃报告,Firebase Crashlytics 提供了四种开箱即用的日志记录机制:自定义键自定义日志用户标识符捕获的异常

添加自定义键

自定义键可以帮助您获取导致崩溃的应用的特定状态。您可以将任意键值对与您的崩溃报告相关联,然后在 Firebase 控制台中查看这些键值对。

[CrashlyticsKit setObjectValue:forKey:] 或以下某个相关方法开始:

- (void)setObjectValue:(id)value forKey:(NSString *)key;

// calls -description on value, perfect for NSStrings!
- (void)setIntValue:(int)value forKey:(NSString *)key;

- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;

- (void)setFloatValue:(float)value forKey:(NSString *)key;

有时您需要更改现有的键值。为此,请调用相同的键,但将值替换掉,例如:

Objective-C
[CrashlyticsKit setIntValue:3 forKey:@"current_level"];
[CrashlyticsKit setObjectValue:@"logged_in" forKey:@"last_UI_action"];
Swift
Crashlytics.sharedInstance().setIntValue(42, forKey: "MeaningOfLife")
Crashlytics.sharedInstance().setObjectValue("Test value", forKey: "last_UI_action")

添加自定义日志消息

要为导致崩溃的事件提供更多背景信息,您可以向您的应用添加自定义 Crashlytics 日志。Crashlytics 会将日志与您的崩溃数据相关联,并在 Firebase 控制台中显示这些日志。

Objective-C

在 Objective-C 中,请使用 CLS_LOG 来帮助查明问题。它会自动包含与日志相关联的 Objective-C 类、方法和行号信息。

在不同的用途下,CLS_LOG 的行为也会不一样,具体取决于它是为调试版本还是发布版本记录日志:

  • 调试版本CLS_LOG会传递至 NSLog,以便您在 Xcode 中以及设备或模拟器上查看输出结果。
  • 发布版本:为了提高性能,CLS_LOG 会抑制所有其他输出结果,并且不会传递至 NSLog

使用 CLS_LOG(format, ...) 即可通过 CLS_LOG 记录日志。例如:

CLS_LOG(@"Higgs-Boson detected! Bailing out... %@", attributesDict);

浏览 Crashlytics/Crashlytics.h 头文件,以便详细了解如何使用 CLS_LOG

Swift

在 Swift 中,请使用 CLSLogvCLSNSLogv 来帮助查明问题。

在使用 CLSLogvCLSNSLogv 记录日志时,需要注意以下两点:

  • 您的格式参数必须是一个编译时常量字符串。在 Objective-C 中,这是由编译器来保证的,但在过渡到 Swift 后暂不具备这项保护功能。
  • 将日志值存储在一个数组中,然后通过对该数组调用 getVaList 来检索这些值。

例如:

func write(string: String) {
    CLSLogv("%@", getVaList([string]))
}
Swift 字符串插值不会生成编译时常量字符串。就像使用 printf 和 NSLog 时一样,在 CLSLog 中使用非常量字符串可能会导致崩溃。

高级

如需更多控制手段,您可以直接使用 CLSLog(format, ...)CLSNSLog(format, ...)。后者会传递至 NSLog,以便您可以在 Xcode 中以及设备或模拟器上查看输出结果。CLSLog(format, ...)CLSNSLog(format, ...) 是线程安全的。CLSLog 用于记录对解决崩溃问题十分重要的信息,不应将其用来跟踪应用内事件。

设置用户标识符

要诊断某个问题,了解哪些用户遇到了特定的崩溃通常很有帮助。Crashlytics 提供了一种在崩溃报告中以匿名方式标识用户的方法。

要将用户 ID 添加到报告中,请以 ID 编号、令牌或哈希值的形式为每个用户分配一个唯一标识符:

Objective-C
[CrashlyticsKit setUserIdentifier:@"123456789"];
Swift
Crashlytics.sharedInstance().setUserIdentifier("123456789")

如果您在设置某个用户标识符后需要将其清除,请将该值重置为空白字符串。清除用户标识符不会移除现有的 Crashlytics 记录。如果您需要删除与用户 ID 关联的记录,请与 Firebase 支持团队联系

记录非严重异常

除了自动报告您的应用中出现的崩溃,Crashlytics 还可让您记录非严重异常。

在 iOS 上,您可以通过记录 NSError 对象来记录非严重异常,Crashlytics 对于这种对象的报告和分组方式与崩溃非常相似:

Objective-C
[CrashlyticsKit recordError:error];
Swift
Crashlytics.sharedInstance().recordError(error)

当使用 recordError 方法时,了解 NSError 的结构以及 Crashlytics 如何使用相关数据对崩溃进行分组是非常重要的。如果对 recordError 方法的使用不正确,可能会导致不可预知的行为,并且可能需要 Crashlytics 在您的应用中对报告所记录错误的功能进行限制。

一个 NSError 对象有三个参数:domain: Stringcode: IntuserInfo: [AnyHashable : Any]? = nil

与根据堆栈轨迹分析结果进行分组的严重崩溃不同,记录的错误是根据 domaincode 来分组的。这是严重崩溃与记录的错误之间的重要区别。例如,日志中记录了如下错误:

NSDictionary *userInfo = @{
    NSLocalizedDescriptionKey: NSLocalizedString(@"The request failed.", nil),
    NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"The response returned a 404.", nil),
    NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Does this page exist?", nil),
    ProductID: @"123456";
    UserID: @"Jane Smith"
};

NSError *error = [NSError domain:NSSomeErrorDomain
                          code:-1001
                          userInfo:userInfo];

这会创建一个根据 NSSomeErrorDomain-1001 分组的新问题。如果记录的其他错误具有与此相同的域和代码值,则将划分到这个问题下。

请避免在网域和代码字段中使用唯一值,例如用户 ID、产品 ID 和时间戳。在这些字段中使用唯一值会导致问题的基数增大,并且可能导致 Crashlytics 需要在您的应用中对报告所记录错误的功能进行限制。应该将唯一值添加到 userInfo Dictionary 对象中。

userInfo 对象中包含的数据会被转换为键值对,并显示在单个问题内的键/日志部分中。

Crashlytics 只存储一个应用会话中最近的 8 次异常。如果您的应用在一个会话中抛出的异常数超过了 8 个,则较早的异常会被舍弃。

日志和自定义键

与崩溃报告类似,您可以通过嵌入日志和自定义键来向 NSError 中添加背景信息。但是,在需要附加什么日志方面,崩溃和记录的错误是有区别的。当崩溃发生并且应用重新启动时,Crashlytics 从磁盘中检索到的日志是截至崩溃那一刻所写入的日志。而当您记录一个 NSError 时,应用并不会立即终止。由于 Crashlytics 只在下一次应用启动时才发送记录的错误报告,并且 Crashlytics 必须限制为日志分配的磁盘空间量,因此有可能出现以下情况:在记录某个 NSError 之后日志空间就已经满了,以至于到了 Crashlytics 从设备发送报告的时候,所有相关的日志都已经被轮替掉了。在记录 NSError 以及在您的应用中使用 CLSLog 和自定义键时,请注意对此进行权衡。

性能考虑因素

请注意,记录 NSError 的开销可能会相当大。当您进行调用时,Crashlytics 会通过一个名为 Stack Unwinding(堆栈展开)的过程来捕获当前线程的调用堆栈。这个过程可能需要占用大量的 CPU 和 I/O 资源,尤其是在支持 DWARF 展开的架构(arm64 和 x86)上。展开过程完成后,信息将同步写入到磁盘中。这可以防止在下一行代码发生崩溃时出现数据丢失现象。

尽管在后台线程中调用此 API 是安全的,但请注意,如果将此调用分发到另一个队列中,则将会丢失当前堆栈轨迹的背景信息。

那 NSException 呢?

Crashlytics 不提供直接记录 NSException 实例的功能。一般来说,Cocoa API 和 Cocoa Touch API 并不具有异常安全性。这意味着使用 @catch 可能会在您的进程中产生非常严重的意想不到的副作用,即使在极其谨慎的情况下使用它也是如此。您任何时候都不应在自己的代码中使用 @catch 语句。请参阅有关该主题的 Apple 文档

启用自选式报告

默认情况下,Firebase Crashlytics 会自动为您的应用的所有用户收集崩溃报告。为了让用户对其发送的数据有更多的控制权,您可以启用自选式报告功能。

为此,您必须停用数据自动收集,并只为选择发送报告的用户初始化 Crashlytics。

  1. 在您的 Info.plist 文件中,使用一个新的键来关闭自动收集功能:
    • 键:firebase_crashlytics_collection_enabled
    • 值:false
  2. 通过在运行时初始化 Crashlytics 来为选定的用户启用收集功能:
    Objective-C
    [Fabric with:@[[Crashlytics class]]];
    Swift
    Fabric.with([Crashlytics.self])

管理 Crash Insights 数据

Crash Insights 会比较您的匿名堆栈轨迹和来自其他 Firebase 应用的跟踪数据,并让您知道您的问题是否属于个例,从而帮助您解决问题。对于许多问题,Crash Insights 甚至会提供资源来帮助您调试崩溃。

Crash Insights 使用汇总的崩溃数据来识别常见的稳定性趋势。 如果您不想分享应用的数据,则可以在 Crash Insights 菜单中选择停用 Crash Insights。此菜单位于 Firebase 控制台的 Crashlytics 问题列表顶部。