App Center (macOS) 損毀

重要

Visual Studio App Center 已排定於 2025 年 3 月 31 日淘汰。 雖然您可以繼續使用 Visual Studio App Center,直到完全淘汰為止,但有數個建議的替代方案可以考慮移轉至。

深入瞭解支持時程表和替代方案。

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

    注意

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

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

  3. 若要停用 App Center SDK 中的撥動,請將金鑰新增 AppCenterApplicationForwarderEnabledInfo.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 使用,它一律會在 start 之前傳回 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])