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 只能在測試/Beta 應用程式中使用,而且不會在生產應用程式中執行任何動作。

[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 使用,它一律會在 start 之前傳回 nil

此 API 有許多使用案例,最常見的是呼叫此 API 並實作其自訂 CrashesDelegate的人員。

自訂 App Center 損毀的使用方式

App Center 當機提供回呼,讓開發人員在將損毀記錄傳送至 App Center 之前和時執行其他動作。

若要新增自訂行為,您必須採用 CrashesDelegate -protocol,其所有方法都是選擇性的。

註冊為委派

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

注意

您必須在呼叫 AppCenter.start之前設定委派,因為 App Center 會在啟動後立即開始處理當機。

應該處理當機嗎?

crashes:shouldProcessErrorReport:如果您想要決定是否需要處理特定損毀,請在採用 -protocol 的 類別 CrashesDelegate 中實作 -method。 例如,您可能想要忽略系統層級損毀,而且您不想傳送至 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: 方法,讓當機正確報告主執行緒上擲回的例外狀況。

  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
    

    注意

    trycatch/ Swift 不適用於 NSException 。 這些例外狀況只能在 Objective-C 中處理。

  2. 開啟Info.plist檔案,並將[主體類別] 欄位中的NSApplication取代為您在此範例中的應用程式類別名稱ReportExceptionApplication

  3. 若要在 App Center SDK中停用雜亂,請將 AppCenterApplicationForwarderEnabled 金鑰新增至 Info.plist 檔案,並將值設定為 0

取得損毀記錄傳送狀態的相關資訊

有時候,您想要知道應用程式當機的狀態。 常見的使用案例是,您可能會想要顯示 UI,告知使用者您的應用程式正在提交當機報告,或者,如果您的 app 在啟動後快速當機,您想要調整應用程式的行為,以確保可以提交當機記錄。 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])