App Center 崩溃 (macOS)

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

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

此外,macOS 上的崩溃日志需要带符号化,请查看说明如何为你的应用程序提供符号的 App Center 诊断文档

备注

在中 4.0.0 引入了 App Center 重大更改的版本。 按照 迁移到 APP CENTER SDK 4.0.0 和更高 版本,从以前的版本迁移 App Center。

扩展中的故障报告

App Center 支持 macOS 扩展中的崩溃报告。 使用方式与在容器应用程序中相同。

生成测试崩溃

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

[MSACCrashes generateTestCrash];
Crashes.generateTestCrash()

获取有关以前的故障的详细信息

App Center 崩溃具有两个 Api,可提供有关应用崩溃情况的详细信息。

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

在启动 SDK 之后的任何时候,你都可以在上一个会话中检查应用是否收到内存警告:

[MSACCrashes hasReceivedMemoryWarningInLastSession];
Crashes.hasReceivedMemoryWarningInLastSession

备注

此方法只能在启动后使用 Crashes ,它将始终返回 NOfalse 在启动之前。

备注

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

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

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

[MSACCrashes hasCrashedInLastSession];
Crashes.hasCrashedInLastSession

如果你想要在发生崩溃后调整应用的行为或 UI,这会很方便。

备注

此方法只能在启动后使用 MSACCrashes ,它将始终返回 NOfalse 在启动之前。

有关最后一个崩溃的详细信息

如果你的应用此前崩溃,你可以获取有关最后一个崩溃的详细信息。

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

备注

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

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

自定义 App Center 崩溃的使用情况

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

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

注册为委托

[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 以请求用户同意。

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

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

  // Your code to present your UI to the user, e.g. an NSAlert.
  NSAlert *alert = [[NSAlert alloc] init];
  [alert setMessageText:@"Sorry about that!"];
  [alert setInformativeText:@"Do you want to send an anonymous crash report so we can fix the issue?"];
  [alert addButtonWithTitle:@"Always send"];
  [alert addButtonWithTitle:@"Send"];
  [alert addButtonWithTitle:@"Don't send"];
  [alert setAlertStyle:NSWarningAlertStyle];

  switch ([alert runModal]) {
  case NSAlertFirstButtonReturn:
    [MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationAlways];
    break;
  case NSAlertSecondButtonReturn:
    [MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationSend];
    break;
  case NSAlertThirdButtonReturn:
    [MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationDontSend];
    break;
  default:
    break;
  }

  return YES; // Return YES if the SDK should await user confirmation, otherwise NO.
})];
Crashes.setUserConfirmationHandler({ (errorReports: [ErrorReport]) in

  // Your code to present your UI to the user, e.g. an NSAlert.
  let alert: NSAlert = NSAlert()
  alert.messageText = "Sorry about that!"
  alert.informativeText = "Do you want to send an anonymous crash report so we can fix the issue?"
  alert.addButton(withTitle: "Always send")
  alert.addButton(withTitle: "Send")
  alert.addButton(withTitle: "Don't send")
  alert.alertStyle = NSWarningAlertStyle

  switch (alert.runModal()) {
  case NSAlertFirstButtonReturn:
    Crashes.notify(with: .always)
    break;
  case NSAlertSecondButtonReturn:
    Crashes.notify(with: .send)
    break;
  case NSAlertThirdButtonReturn:
    Crashes.notify(with: .dontSend)
    break;
  default:
    break;
  }

  return true // Return true if the SDK should await user confirmation, otherwise return false.
})

如果返回上述处理程序块,应用应获取用户权限,并借助以下 API 向 SDK 发送消息 YES / true ,并返回结果。 如果使用警报(如上述示例中所示)时,将基于调用结果 (ModalResponse) runModal 调用它。

// Depending on the user'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.
Crashes.notify(with: .dontSend)
Crashes.notify(with: .send)
Crashes.notify(with: .always)

启用捕获在主线程上引发的未捕获异常

AppKit 捕获主线程上引发的异常,防止应用程序在 macOS 上崩溃,因此 SDK 无法捕获这些崩溃。 为了模拟 iOS 行为,在 SDK 初始化之前设置标志,此标志允许应用程序在未捕获的异常时 NSApplicationCrashOnExceptions 崩溃,SDK 可以报告它们。

[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions" : @YES }];
UserDefaults.standard.register(defaults: ["NSApplicationCrashOnExceptions": true])

备注

App Center SDK 在 1.10.0 及以下版本中自动设置 标志。 从版本 1.11.0 开始,不再自动设置此标志。

禁止转发应用程序主类的方法调用,以App Center崩溃

Crashes App Center SDK 通过向自身转发应用程序主类的一些方法调用,使用"崩溃"来改进其集成。 方法旋转是一种在运行时更改方法实现的方法。 如果出于任何原因(例如,由于特定策略) )而不想使用令人困惑的 (,应自己重写应用程序的 和 方法,以便崩溃正确报告在主线程上引发的 reportException: sendEvent: 异常。

  1. 创建 ReportExceptionApplication.m 文件并添加以下实现:

    @import Cocoa;
    @import AppCenterCrashes;
    
    @interface ReportExceptionApplication : NSApplication
    @end
    
    @implementation ReportExceptionApplication
    
    - (void)reportException:(NSException *)exception {
      [MSACCrashes applicationDidReportException:exception];
      [super reportException:exception];
    }
    
    - (void)sendEvent:(NSEvent *)theEvent {
      @try {
        [super sendEvent:theEvent];
      } @catch (NSException *exception) {
        [self reportException:exception];
      }
    }
    
    @end
    

    备注

    Swift try / catch 的 不与 一起工作 NSException 。 这些异常只能在 Objective-C 中处理。

  2. 打开 info.plist 文件,并将 主体类 字段中的 NSApplication 替换为应用程序类名称,在本示例中为 ReportExceptionApplication

  3. 若要禁用 APP CENTER SDK 中的 swizzling,请将该 AppCenterApplicationForwarderEnabled 密钥添加到 info.plist 文件中,并将值设置为 0

获取有关故障日志发送状态的信息

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

在 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 之前返回。

禁用 Mach-o 异常处理

默认情况下,App Center 崩溃使用 Mach-o 异常处理程序通过 Mach-o 异常服务器捕获严重信号,如堆栈溢出。

disableMachExceptionHandler-方法提供禁止通过 mach-o 异常服务器捕获严重信号的选项。 如果要禁用 Mach-o 异常处理程序,则应在启动 SDK 之前 调用此方法。 典型的安装代码将如下所示:

[MSACCrashes disableMachExceptionHandler];
[MSACAppCenter start:@"{Your App Secret}" withServices:@[[MSACAnalytics class], [MSACCrashes class]]];
Crashes.disableMachExceptionHandler()
AppCenter.start(withAppSecret: "{Your App Secret}", services: [Analytics.self, Crashes.self])