App Center 崩溃 (tvOS)

重要

Visual Studio App Center 计划于 2025 年 3 月 31 日停用。 虽然可以继续使用 Visual Studio App Center,直到它完全停用,但你可以考虑迁移到几个建议的替代方法。

详细了解支持时间线和替代方案。

每次应用崩溃时,App Center 崩溃都会自动生成崩溃日志。 日志首先写入设备的存储,当用户再次启动应用时,故障报告将发送到 App Center。 收集崩溃适用于 beta 和实时应用,即提交到App Store的应用。 崩溃日志包含有价值的信息,可帮助你修复故障。

如果尚未在应用程序中设置 SDK,请按照入门部分进行操作。

此外,tvOS 上的崩溃日志需要符号化,检查 App Center Diagnostics 文档来说明如何为应用提供符号。

注意

若要接收正确符号化的堆栈跟踪,请确保已禁用位代码。 可以在 App Center 的 iOS 符号化文档中了解有关位代码的详细信息。

注意

4.0.0 App Center 版本中引入了中断性变更。 按照 迁移到 App Center SDK 4.0.0 及更高 版本部分从以前的版本迁移 App Center。

生成测试崩溃

App Center 崩溃提供了一个 API,用于生成测试崩溃,以便轻松测试 SDK。 此 API 只能在测试/beta 应用中使用,不会在生产应用中执行任何操作。

[MSACCrashes generateTestCrash];
Crashes.generateTestCrash()

获取有关以前崩溃的详细信息

App Center 崩溃有两个 API,可在应用崩溃时提供详细信息。

应用在上一个会话中是否收到内存不足警告?

启动 SDK 后,可以随时检查应用是否在上一个会话中收到内存警告:

[MSACCrashes hasReceivedMemoryWarningInLastSession];
Crashes.hasReceivedMemoryWarningInLastSession

注意

此方法必须仅在启动后 Crashes 使用,它始终返回 NO 或在 false 启动之前。

注意

在某些情况下,内存不足的设备无法发送事件。

应用是否在上一个会话中崩溃?

启动 SDK 后,可以随时检查应用在上一次启动时崩溃:

[MSACCrashes hasCrashedInLastSession];
Crashes.hasCrashedInLastSession

如果想要在发生崩溃后调整应用的行为或 UI,这非常有用。

注意

此方法必须仅在启动后 MSACCrashes 使用,它始终返回 NO 或在 false 启动之前。

有关上次崩溃的详细信息

如果你的应用以前崩溃,你可以获取有关上次崩溃的详细信息。

MSACErrorReport *crashReport = [MSACCrashes lastSessionCrashReport];
var crashReport = Crashes.lastSessionCrashReport

注意

此方法只能在启动后 Crashes 使用,它始终在启动前返回 nil

此 API 有许多用例,最常见的用例是调用此 API 并实现其自定义 CrashesDelegate 的人员。

自定义 App Center 崩溃的用法

App Center 崩溃为开发人员提供回调,以便在将崩溃日志发送到 App Center 之前和向 App Center 发送时执行其他操作。

若要添加自定义行为,需要采用 CrashesDelegate-protocol,其所有方法都是可选的。

注册为代理人

[MSACCrashes setDelegate:self];
Crashes.delegate = self

注意

必须在调用 AppCenter.start之前设置委托,因为 App Center 在启动后立即开始处理崩溃。

是否应处理崩溃?

crashes:shouldProcessErrorReport:如果要确定是否需要处理特定故障,在采用 CrashesDelegate-协议的 类中实现 -方法。 例如,你可能希望忽略系统级别崩溃,并且不希望发送到 App Center。

- (BOOL)crashes:(MSACCrashes *)crashes shouldProcessErrorReport:(MSACErrorReport *)errorReport {
  return YES; // return YES if the crash report should be processed, otherwise NO.
}
func crashes(_ crashes: Crashes, shouldProcess errorReport: ErrorReport) -> Bool {
  return true; // return true if the crash report should be processed, otherwise false.
}

已处理错误

App Center 还允许通过 方法使用已处理的异常 trackError 来跟踪错误。 应用可以选择将属性或/和附件附加到已处理的错误报告,以提供进一步的上下文。

@try {
  // Throw error.
} @catch (NSError *error) {

  // Init attachments.
  NSArray<MSACErrorAttachmentLog *> attachments = @[ MSACErrorAttachmentLog attachmentWithText:@"Hello world!" filename:@"hello.txt"] ]

  // Init properties.
  NSDictionary *properties = @{ "Category" : "Music", "Wifi" : "On" };

  // Track errors.
  [MSACCrashes trackError:error withProperties:properties attachments:attachments];
  [MSACCrashes trackError:error withProperties:properties attachments:nil];
  [MSACCrashes trackError:error withProperties:nil attachments:attachments];
  [MSACCrashes trackError:error withProperties:nil attachments:nil];
}
do {
  // Throw error.
} catch {

  // Init attachments.
  let attachments = [ErrorAttachmentLog.attachment(withText: "Hello world!", filename: "hello.txt")]

  // Init properties.
  let properties:Dictionary<String, String> = ["Category" : "Music", "Wifi" : "On"]

  // Track errors.
  Crashes.trackError(error, properties: properties, attachments: attachments)
  Crashes.trackError(error, properties: properties, attachments: nil)
  Crashes.trackError(error, properties: nil, attachments: attachments)
  Crashes.trackError(error, properties: nil, attachments: nil)
}

对于跟踪异常,可以使用 trackException 方法:

@try {
  // Throw exceptions.
} @catch (NSException *exception) {

  // Init exceptions.
  MSACExceptionModel *customException1 = [MSACExceptionModel initWithType:@"Custom exception" exceptionMessage:"Track custom exception.", stackTrace:exception.callStackSymbols];
  MSACExceptionModel *customException2 = [MSACExceptionModel initWithException:exception];

  // Track exceptions.
  [MSACCrashes trackException:customException1 withProperties:properties attachments:nil];
  [MSACCrashes trackException:customException2 withProperties:properties attachments:nil];
}
do {
  // Throw exception.
} catch {

  // Init exception.
  let exception = ExceptionModel(withType: "Custom exception", exceptionMessage: "Track custom exception.", stackTrace: Thread.callStackSymbols)

  // Track exception.
  Crashes.trackException(exception, properties: properties, attachments: nil)
}

如果用户隐私对你很重要,你可能希望在将故障报告发送到 App Center 之前获得用户的确认。 SDK 公开一个回调,告知 App Center 崩溃在发送任何故障报告之前等待用户的确认。

如果选择这样做,则负责获取用户的确认,例如,通过对话框提示并使用以下选项之一: 始终发送发送不发送。 根据输入,你将告诉 App Center 崩溃要执行的操作,然后会相应地处理崩溃。

注意

SDK 不显示此对话框,应用必须提供自己的 UI 以请求用户同意。

注意

如果应用未实现用户确认对话框,则不应显式调用 notifyWithUserConfirmation ;崩溃模块将隐式处理发送日志。

以下方法演示如何设置用户确认处理程序:

[MSACCrashes setUserConfirmationHandler:(^(NSArray<MSACErrorReport *> *errorReports) {

  // Your code to present your UI to the user, e.g. an UIAlertController.
  UIAlertController *alertController = [UIAlertController
      alertControllerWithTitle:@"Sorry about that!"
                      message:@"Do you want to send an anonymous crash report so we can fix the issue?"
                preferredStyle:UIAlertControllerStyleAlert];

  [alertController
      addAction:[UIAlertAction actionWithTitle:@"Don't send"
                                        style:UIAlertActionStyleCancel
                                      handler:^(UIAlertAction *action) {
                                        [MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationDontSend];
                                      }]];

  [alertController
      addAction:[UIAlertAction actionWithTitle:@"Send"
                                        style:UIAlertActionStyleDefault
                                      handler:^(UIAlertAction *action) {
                                        [MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationSend];
                                      }]];

  [alertController
      addAction:[UIAlertAction actionWithTitle:@"Always send"
                                        style:UIAlertActionStyleDefault
                                      handler:^(UIAlertAction *action) {
                                        [MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationAlways];
                                      }]];
  // Show the alert controller.
  [self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
  return YES; // Return YES if the SDK should await user confirmation, otherwise NO.
})];
MSACCrashes.setUserConfirmationHandler({ (errorReports: [MSACErrorReport]) in

  // Your code to present your UI to the user, e.g. an UIAlertController.
  let alertController = UIAlertController(title: "Sorry about that!",
                                          message: "Do you want to send an anonymous crash report so we can fix the issue?",
                                          preferredStyle:.alert)

  alertController.addAction(UIAlertAction(title: "Don't send", style: .cancel) {_ in
    MSACCrashes.notify(with: .dontSend)
  })

  alertController.addAction(UIAlertAction(title: "Send", style: .default) {_ in
    MSACCrashes.notify(with: .send)
  })

  alertController.addAction(UIAlertAction(title: "Always send", style: .default) {_ in
    MSACCrashes.notify(with: .always)
  })

  // Show the alert controller.
  self.window?.rootViewController?.present(alertController, animated: true)
  return true // Return true if the SDK should await user confirmation, otherwise return false.
})

如果返回 YES/true 上述处理程序块,应用应获取用户权限,并使用以下 API 向 SDK 发送结果消息。 如果为此使用警报,如上面的示例中所做的那样,你会从 -callback 的 alertView:clickedButtonAtIndex:实现中调用它。

// Depending on the users's choice, call notifyWithUserConfirmation: with the right value.
[MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationDontSend];
[MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationSend];
[MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationAlways];
// Depending on the user's choice, call notify(with:) with the right value.
MSACCrashes.notify(with: .dontSend)
MSACCrashes.notify(with: .send)
MSACCrashes.notify(with: .always)

获取有关崩溃日志的发送状态的信息

有时,你想知道应用崩溃的状态。 一个常见的用例是,你可能想要显示 UI 来告知用户你的应用正在提交崩溃报告,或者,如果你的应用在启动后快速崩溃,你需要调整应用的行为,以确保可以提交崩溃日志。 CrashesDelegate-protocol 定义了三个不同的回调,你可以在应用中使用这些回调,以便收到有关所发生情况的通知:

在 SDK 发送崩溃日志之前,将调用以下回调

- (void)crashes:(MSACCrashes *)crashes willSendErrorReport:(MSACErrorReport *)errorReport {
  // Your code, e.g. to present a custom UI.
}
func crashes(_ crashes: Crashes, willSend errorReport: ErrorReport) {
  // Your code, e.g. to present a custom UI.
}

如果终结点出现网络问题或中断,并且重启应用, willSendErrorReport 则会在进程重启后再次触发。

SDK 成功发送崩溃日志后,将调用以下回调

- (void)crashes:(MSACCrashes *)crashes didSucceedSendingErrorReport:(MSACErrorReport *)errorReport {
  // Your code, e.g. to hide the custom UI.
}
func crashes(_ crashes: Crashes, didSucceedSending errorReport: ErrorReport) {
  // Your code goes here.
}

如果 SDK 未能发送故障日志,将调用以下回调

- (void)crashes:(MSACCrashes *)crashes didFailSendingErrorReport:(MSACErrorReport *)errorReport withError:(NSError *)error {
  // Your code goes here.
}
func crashes(_ crashes: Crashes, didFailSending errorReport: ErrorReport, withError error: Error) {
  // Your code goes here.
}

接收 didFailSendingErrorReport 表示发生了不可恢复的错误,例如 4xx 代码。 例如, 401 表示 appSecret 错误。

如果这是网络问题,则不会触发此回调。 在这种情况下,SDK 会继续重试 (,并在网络连接关闭) 时暂停重试。

向崩溃报告添加附件

可以将二进制附件和文本附件添加到崩溃报告。 SDK 会连同崩溃一起发送它们,以便你可以在 App Center 门户中看到它们。 在从以前的应用程序启动时发送存储的故障之前,将立即调用以下回调。 发生崩溃时,不会调用它。 下面是如何将文本和图像附加到崩溃的示例:

- (NSArray<MSACErrorAttachmentLog *> *)attachmentsWithCrashes:(MSACCrashes *)crashes
                                             forErrorReport:(MSACErrorReport *)errorReport {
  MSACErrorAttachmentLog *attachment1 = [MSACErrorAttachmentLog attachmentWithText:@"Hello world!" filename:@"hello.txt"];
  MSACErrorAttachmentLog *attachment2 = [MSACErrorAttachmentLog attachmentWithBinary:[@"Fake image" dataUsingEncoding:NSUTF8StringEncoding] filename:@"fake_image.jpeg" contentType:@"image/jpeg"];
  return @[ attachment1, attachment2 ];
}
func attachments(with crashes: Crashes, for errorReport: ErrorReport) -> [ErrorAttachmentLog]? {
  let attachment1 = ErrorAttachmentLog.attachment(withText: "Hello world!", filename: "hello.txt")
  let attachment2 = ErrorAttachmentLog.attachment(withBinary: "Fake image".data(using: String.Encoding.utf8), filename: nil, contentType: "image/jpeg")
  return [attachment1!, attachment2!]
}

注意

大小限制当前为 7 MB。 尝试发送较大的附件将触发错误。

在运行时启用或禁用 App Center 崩溃

可以在运行时启用和禁用 App Center 崩溃。 如果禁用它,SDK 不会为应用执行任何崩溃报告。

[MSACCrashes setEnabled:NO];
Crashes.enabled = false

若要再次启用 App Center 崩溃,请使用同一 API,但作为参数传递 YES/true

[MSACCrashes setEnabled:YES];
Crashes.enabled = true

状态在应用程序启动时保留在设备的存储中。

注意

只有在启动后 Crashes 才能使用此方法。

检查是否启用了 App Center 崩溃

还可以检查是否启用 App Center 崩溃:

BOOL enabled = [MSACCrashes isEnabled];
var enabled = Crashes.enabled

注意

此方法只能在启动后 Crashes 使用,它始终在启动前返回 false