Udostępnij za pośrednictwem


Awarie usługi App Center (macOS)

Ważne

Program Visual Studio App Center został wycofany 31 marca 2025 r. z wyjątkiem funkcji analizy i diagnostyki, które będą nadal obsługiwane do 30 czerwca 2026 r. Dowiedz się więcej.

Awarie usługi App Center automatycznie generują dziennik awarii za każdym razem, gdy aplikacja ulegnie awarii. Dziennik jest najpierw zapisywany w magazynie urządzenia, a gdy użytkownik ponownie uruchomi aplikację, raport o awarii zostanie wysłany do Centrum aplikacji. Zbieranie awarii działa zarówno w przypadku aplikacji beta, jak i wersji produkcyjnych, czyli tych, które zostały przesłane do App Store. Dzienniki awarii zawierają cenne informacje ułatwiające naprawienie awarii.

Postępuj zgodnie z sekcją Wprowadzenie , jeśli zestaw SDK nie został jeszcze skonfigurowany w aplikacji.

Ponadto dzienniki awaryjne w systemie macOS wymagają symboliczności, zapoznaj się z dokumentacją diagnostyki Centrum aplikacji , w której wyjaśniono, jak dostarczać symbole dla aplikacji.

Uwaga / Notatka

W wersji 4.0.0 App Center wprowadzono zmiany powodujące niezgodność. Postępuj zgodnie z sekcją Migrate to App Center SDK 4.0.0 and higher (Migrowanie do zestawu APP Center SDK 4.0.0 i nowszych ), aby przeprowadzić migrację centrum aplikacji z poprzednich wersji.

Raportowanie awarii w rozszerzeniach

Usługa App Center obsługuje raportowanie awarii w rozszerzeniach systemu macOS. Użycie jest takie samo jak w aplikacji kontenera.

Generowanie awarii testowej

App Center Crashes zapewnia interfejs API do generowania testowej awarii w celu łatwego testowania SDK. Ten interfejs API może być używany tylko w aplikacjach testowych/beta i nie będzie wykonywać żadnych czynności w aplikacjach produkcyjnych.

[MSACCrashes generateTestCrash];
Crashes.generateTestCrash()

Uzyskaj więcej informacji o poprzedniej awarii

Usługa App Center Crash ma dwa interfejsy API, które zapewniają więcej informacji na wypadek awarii aplikacji.

Czy aplikacja otrzymała ostrzeżenie o niskiej ilości pamięci w poprzedniej sesji?

W dowolnym momencie po uruchomieniu zestawu SDK możesz sprawdzić, czy aplikacja otrzymała ostrzeżenie o pamięci w poprzedniej sesji:

[MSACCrashes hasReceivedMemoryWarningInLastSession];
Crashes.hasReceivedMemoryWarningInLastSession

Uwaga / Notatka

Ta metoda musi być używana tylko po Crashes uruchomieniu, zawsze będzie zwracać NO lub false przed rozpoczęciem.

Uwaga / Notatka

W niektórych przypadkach urządzenie z małą ilością pamięci nie może wysyłać zdarzeń.

Czy aplikacja uległa awarii w poprzedniej sesji?

W dowolnym momencie po uruchomieniu zestawu SDK możesz sprawdzić, czy aplikacja uległa awarii w poprzednim uruchomieniu:

[MSACCrashes hasCrashedInLastSession];
Crashes.hasCrashedInLastSession

Jest to przydatne w przypadku, gdy chcesz dostosować zachowanie lub interfejs użytkownika aplikacji po wystąpieniu awarii.

Uwaga / Notatka

Ta metoda musi być używana tylko po MSACCrashes uruchomieniu, zawsze będzie zwracać NO lub false przed rozpoczęciem.

Szczegóły dotyczące ostatniej awarii

Jeśli aplikacja uległa awarii wcześniej, możesz uzyskać szczegółowe informacje o ostatniej awarii.

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

Uwaga / Notatka

Ta metoda musi być używana tylko po uruchomieniu Crashes. Zawsze zwróci nil przed rozpoczęciem.

W przypadku tego interfejsu API istnieje wiele przypadków użycia, najczęściej spotykane są osoby, które nazywają ten interfejs API i implementują niestandardowe awarieDelegate.

Dostosowywanie użytkowania funkcji App Center Crashes

Usługa App Center Crash udostępnia wywołania zwrotne dla deweloperów do wykonywania dodatkowych akcji przed i podczas wysyłania dzienników awarii do Centrum aplikacji.

Aby dodać zachowanie niestandardowe, należy zaadoptować protokół CrashesDelegate, wszystkie jego metody są opcjonalne.

Zarejestruj się jako pełnomocnik

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

Uwaga / Notatka

Musisz ustawić delegata przed wywołaniem metody AppCenter.start, ponieważ Centrum Aplikacji rozpoczyna przetwarzanie błędów natychmiast po uruchomieniu.

Czy awaria powinna zostać przetworzona?

Zaimplementuj metodę crashes:shouldProcessErrorReport: w klasie, która przyjmuje protokół CrashesDelegate, jeśli chcesz zdecydować, czy należy przetworzyć konkretną awarię, czy nie. Na przykład może wystąpić awaria na poziomie systemu, którą chcesz zignorować i że nie chcesz wysyłać do Centrum aplikacji.

- (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.
}

Zarządzane błędy

Usługa App Center umożliwia również monitorowanie błędów przy użyciu obsługiwanych wyjątków metodą trackError. Aplikacja może opcjonalnie dołączyć właściwości lub/i załączniki do obsługiwanego raportu o błędach w celu zapewnienia dalszego kontekstu.

@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)
}

Aby śledzić wyjątki, można użyć metody 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)
}

Jeśli prywatność użytkownika jest dla Ciebie ważna, możesz uzyskać potwierdzenie użytkownika przed wysłaniem raportu o awarii do Centrum aplikacji. SDK udostępnia wywołanie zwrotne, które informuje funkcję App Center Crashes o konieczności oczekiwania na potwierdzenie użytkownika przed wysłaniem raportów o awariach.

Jeśli zdecydujesz się to zrobić, odpowiadasz za uzyskanie potwierdzenia użytkownika, np. za pośrednictwem okna dialogowego z jedną z następujących opcji: Zawsze wysyłaj, Wysyłaj i nie wysyłaj. Na podstawie danych wejściowych poinstruujesz App Center Crashes, co należy zrobić, a awaria zostanie odpowiednio obsłużona.

Uwaga / Notatka

Zestaw SDK nie wyświetla okna dialogowego; aplikacja musi zapewnić własny interfejs użytkownika, aby uzyskać zgodę użytkownika.

Poniższa metoda pokazuje, jak skonfigurować procedurę obsługi potwierdzenia użytkownika:

[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.
})

Jeśli zwrócisz YES/true w powyższym bloku obsługi, aplikacja powinna uzyskać uprawnienia użytkownika i poinformować zestaw SDK o wyniku za pomocą poniższego interfejsu API. Jeśli używasz dla tego alertu, tak jak w powyższym przykładzie, wywołasz go na podstawie wyniku (runModal) wywołania.

// 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)

Włącz przechwytywanie nieuchwyconych wyjątków zgłaszanych w wątku głównym

Zestaw AppKit przechwytuje wyjątki zgłaszane w wątku głównym, zapobiegając awarii aplikacji w systemie macOS, co uniemożliwia zestawowi SDK przechwycenie tych awarii. Aby naśladować zachowanie systemu iOS, ustaw flagę NSApplicationCrashOnExceptions przed zainicjowaniem SDK. Dzięki tej fladze aplikacja może się zawiesić w przypadku nieuchwyconych wyjątków, a SDK będzie mogło je zgłaszać.

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

Uwaga / Notatka

Zestaw SDK usługi App Center ustawił flagę automatycznie w wersjach 1.10.0 i nowszych. Począwszy od wersji 1.11.0 ta flaga nie jest już ustawiana automatycznie.

Wyłącz przekazywanie wywołań metod klasy głównej aplikacji do usługi App Center Crashes.

Zestaw SDK awarii usługi App Center używa swizzlingu, aby ulepszyć integrację, przekierowując do siebie niektóre wywołania metod głównej klasy aplikacji. Modyfikowanie metody to sposób zmiany implementacji metod w czasie wykonywania programu. Jeśli z jakiegokolwiek powodu nie chcesz używać wizzlingu (np. ze względu na określone zasady), należy samodzielnie zastąpić metody reportException: i sendEvent: aplikacji, aby poprawnie zgłaszać wyjątki występujące w głównym wątku.

  1. Utwórz plik ReportExceptionApplication.m i dodaj następującą implementację:

    @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
    

    Uwaga / Notatka

    try / catch Swift nie współpracuje z NSException. Te wyjątki można obsługiwać tylko w Objective-C.

  2. Otwórz plik Info.plist i zastąp NSApplication w polu głównej klasy nazwą klasy twojej aplikacji, na przykład ReportExceptionApplication.

  3. Aby wyłączyć swizzling w App Center SDK, dodaj klucz AppCenterApplicationForwarderEnabled do pliku Info.plist i ustaw jego wartość na 0.

Uzyskaj informacje o stanie wysyłki dziennika awarii

Czasami chcesz poznać stan awarii aplikacji. Typowy przypadek użycia polega na tym, że możesz pokazać interfejs użytkownika, który informuje użytkowników, że aplikacja przesyła raport o awarii lub w przypadku, gdy aplikacja ulega awarii szybko po uruchomieniu, chcesz dostosować zachowanie aplikacji, aby upewnić się, że dzienniki awarii można przesłać. Protokół CrashesDelegate-protocol definiuje trzy różne wywołania zwrotne, których można użyć w aplikacji, aby otrzymywać powiadomienia o tym, co się dzieje:

Następujące wywołanie zwrotne zostanie wywołane przed wysłaniem dziennika awarii przez zestaw 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.
}

W przypadku problemów z siecią lub awarii w punkcie końcowym i ponownego uruchomienia aplikacji willSendErrorReport zostanie wyzwolony ponownie po ponownym uruchomieniu procesu.

Następujące wywołanie zwrotne zostanie wywołane po pomyślnym wysłaniu dziennika awarii przez zestaw 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.
}

Następujące wywołanie zwrotne zostanie wywołane, jeśli zestaw SDK nie może wysłać dziennika awarii

- (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.
}

Odbieranie didFailSendingErrorReport oznacza, że wystąpił błąd niemożliwy do odzyskania, taki jak kod 4xx . Na przykład 401 oznacza, że appSecret jest nieprawidłowy.

Ten callback nie zostanie wywołany, jeśli jest to problem z siecią. W takim przypadku zestaw SDK ponawia próbę (a także wstrzymuje ponawianie próby, gdy połączenie sieciowe nie działa).

Dodawanie załączników do raportu o awarii

Do raportu o awarii można dodawać załączniki binarne i tekstowe. Zestaw SDK wyśle je wraz z awarią, aby można było je zobaczyć w portalu usługi App Center. Następujące wywołanie zwrotne zostanie wywołane bezpośrednio przed wysłaniem przechowywanej awarii z poprzednich uruchomień aplikacji. Nie będzie wywoływana, gdy wystąpi awaria. Oto przykład dołączania tekstu i obrazu do awarii:

- (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!]
}

Uwaga / Notatka

Limit rozmiaru wynosi obecnie 7 MB. Próba wysłania większego załącznika spowoduje błąd.

Włączanie lub wyłączanie funkcji raportowania awarii w App Center w czasie wykonywania

Możesz włączyć i wyłączyć funkcję zarządzania awariami w usłudze App Center w czasie wykonywania. Jeśli go wyłączysz, zestaw SDK nie będzie wykonywać żadnych raportów dotyczących awarii dla aplikacji.

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

Aby ponownie włączyć funkcję App Center Crashes, użyj tego samego interfejsu API, ale przekaż YES/true jako parametr.

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

Stan jest utrwalany w magazynie urządzenia w ramach uruchamiania aplikacji.

Uwaga / Notatka

Ta metoda musi być używana tylko po uruchomieniu Crashes.

Sprawdź, czy raportowanie awarii w App Center jest włączone

Możesz również sprawdzić, czy usługa App Center Ulega awarii jest włączona, czy nie:

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

Uwaga / Notatka

Ta metoda musi być używana tylko po uruchomieniu Crashes. Zawsze zwróci false przed rozpoczęciem.

Wyłączanie obsługi wyjątków Mach

Domyślnie App Center Crashes używa programu obsługi wyjątków Mach do przechwytywania sygnałów krytycznych, np. przepełnienia stosu, za pośrednictwem serwera wyjątków Mach.

Metoda disableMachExceptionHandler zapewnia opcję wyłączenia przechwytywania krytycznych sygnałów za pośrednictwem serwera wyjątków Mach. Jeśli chcesz wyłączyć obsługę wyjątków Mach, powinno się wywołać tę metodę PRZED uruchomieniem SDK. Typowy kod konfiguracji wygląda następująco:

[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])