重要
Visual Studio App Center 于 2025 年 3 月 31 日停用,但分析和诊断功能除外,这些功能将继续受支持,直到 2026 年 6 月 30 日。 了解详细信息。
每次应用发生崩溃时,App Center Crashes 功能都会自动生成一份崩溃日志。 日志首先写入设备的存储,当用户再次启动应用时,崩溃报告将发送到 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 只能在测试/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 之前和时执行其他操作。
若要添加自定义行为,需要采用 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 才能请求用户同意。
以下方法演示如何设置用户确认处理程序:
[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.
})
如果在上面的处理程序块中返回 YES
/true
,您的应用应获取用户权限,然后使用以下 API 将结果发送给 SDK。 如果对此使用警报,正如我们在上面的示例中所做的那样,你会根据调用的结果(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 崩溃的应用程序主类方法调用的转发
App Center 崩溃报告 SDK 使用方法调配来改进其集成,通过将应用程序主类中的某些方法调用转发至它自己。 方法重排是一种在运行时更改方法实现的方法。 如果出于任何原因而不想使用重排(例如,由于特定策略),则应自行重写应用程序的 reportException:
和 sendEvent:
方法,以便崩溃报告在主线程上正确引发的异常。
创建 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 中处理。打开 Info.plist 文件,并将 Principal 类字段中的 NSApplication 替换为应用程序类名称 ReportExceptionApplication 在本示例中。
若要在 App Center SDK 中禁用重排,请将
AppCenterApplicationForwarderEnabled
密钥添加到 Info.plist 文件,并将值0
设置为 。
获取有关故障日志的发送状态的信息
有时,你想知道应用崩溃的状态。 常见的用例是,你可能想要显示 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
。
禁用 Mach 异常处理
默认情况下,App Center 崩溃使用 Mach 异常处理程序通过 Mach 异常服务器捕获致命信号,例如堆栈溢出。
disableMachExceptionHandler
-method 提供了一个选项,用于通过 Mach 异常服务器禁用捕获致命信号。 如果要禁用 Mach 异常处理程序,应在启动 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])