Condividi tramite


Arresti anomali di App Center (macOS)

Importante

Visual Studio App Center è previsto per il ritiro il 31 marzo 2025. Anche se è possibile continuare a usare Visual Studio App Center fino a quando non viene completamente ritirato, esistono diverse alternative consigliate che è possibile considerare la migrazione a.

Altre informazioni sulle sequenze temporali di supporto e sulle alternative.

Gli arresti anomali di App Center genereranno automaticamente un log di arresto anomalo ogni volta che l'app si arresta in modo anomalo. Il log viene prima scritto nella risorsa di archiviazione del dispositivo e quando l'utente avvia di nuovo l'app, il report di arresto anomalo verrà inviato a App Center. La raccolta di arresti anomali funziona sia per le app beta che per le app live, ad esempio quelle inviate all'App Store. I log di arresto anomalo contengono informazioni preziose per facilitare la correzione dell'arresto anomalo.

Seguire la sezione Introduzione se non è ancora stato configurato l'SDK nell'applicazione.

Inoltre, i log degli arresti anomali in macOS richiedono simbolicamente, vedere la documentazione di Diagnostica di App Center che illustra come fornire simboli per l'app.

Nota

4.0.0 Nella versione di App Center sono state introdotte modifiche di rilievo. Seguire la sezione Migrate to App Center SDK 4.0.0 e versioni successive per eseguire la migrazione di App Center dalle versioni precedenti.

Creazione di report di arresto anomalo nelle estensioni

App Center supporta la creazione di report di arresto anomalo nelle estensioni macOS. L'utilizzo è uguale a quello dell'applicazione contenitore.

Generare un arresto anomalo del test

Gli arresti anomali di App Center offrono un'API per generare un arresto anomalo del test per un semplice test dell'SDK. Questa API può essere usata solo nelle app test/beta e non eseguirà alcuna operazione nelle app di produzione.

[MSACCrashes generateTestCrash];
Crashes.generateTestCrash()

Ottenere altre informazioni su un arresto anomalo precedente

Gli arresti anomali di App Center hanno due API che forniscono altre informazioni in caso di arresto anomalo dell'app.

L'app ha ricevuto un avviso di memoria insufficiente nella sessione precedente?

In qualsiasi momento dopo l'avvio dell'SDK, è possibile verificare se l'app ha ricevuto un avviso di memoria nella sessione precedente:

[MSACCrashes hasReceivedMemoryWarningInLastSession];
Crashes.hasReceivedMemoryWarningInLastSession

Nota

Questo metodo deve essere usato solo dopo Crashes l'avvio, restituirà sempre NO o false prima dell'avvio.

Nota

In alcuni casi, un dispositivo con memoria ridotta non può inviare eventi.

L'app si è arrestata in modo anomalo nella sessione precedente?

In qualsiasi momento dopo l'avvio dell'SDK, è possibile verificare se l'app si è arrestata in modo anomalo nell'avvio precedente:

[MSACCrashes hasCrashedInLastSession];
Crashes.hasCrashedInLastSession

Questo è utile nel caso in cui si vuole modificare il comportamento o l'interfaccia utente dell'app dopo un arresto anomalo.

Nota

Questo metodo deve essere usato solo dopo MSACCrashes l'avvio, restituirà sempre NO o false prima dell'avvio.

Dettagli sull'ultimo arresto anomalo

Se l'app si è bloccata in precedenza, è possibile ottenere informazioni dettagliate sull'ultimo arresto anomalo.

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

Nota

Questo metodo deve essere usato solo dopo Crashes l'avvio, verrà sempre restituito nil prima dell'avvio.

Esistono numerosi casi d'uso per questa API, quello più comune è la gente che chiama questa API e implementa i propri crash personalizzatiDelegate.

Personalizzare l'utilizzo degli arresti anomali di App Center

Gli arresti anomali di App Center offrono callback per gli sviluppatori per eseguire azioni aggiuntive prima e quando si inviano log di arresto anomalo a App Center.

Per aggiungere il comportamento personalizzato, è necessario adottare il CrashesDelegateprotocollo -, tutti i relativi metodi sono facoltativi.

Registrare come delegato

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

Nota

È necessario impostare il delegato prima di chiamare AppCenter.start, poiché App Center avvia l'elaborazione si arresta in modo anomalo immediatamente dopo l'avvio.

L'arresto anomalo deve essere elaborato?

Implementare il metodo -nella classe che adotta il crashes:shouldProcessErrorReport:CrashesDelegateprotocollo -se si vuole decidere se è necessario elaborare o meno un determinato arresto anomalo. Ad esempio, potrebbe verificarsi un arresto anomalo a livello di sistema che si vuole ignorare e che non si vuole inviare a 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.
}

Errori gestiti

App Center consente anche di tenere traccia degli errori usando eccezioni gestite tramite trackError metodo. Un'app può facoltativamente collegare proprietà o/o allegati a un report di errore gestito per fornire un ulteriore contesto.

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

Per tenere traccia delle eccezioni, è possibile usare trackException il metodo:

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

Se la privacy degli utenti è importante per te, potresti voler ottenere la conferma dell'utente prima di inviare un report di arresto anomalo all'App Center. L'SDK espone un callback che indica agli arresti anomali di App Center di attendere la conferma dell'utente prima di inviare eventuali report di arresto anomalo.

Se si sceglie di farlo, si è responsabili dell'acquisizione della conferma dell'utente, ad esempio tramite una richiesta di dialogo con una delle opzioni seguenti: Invia sempre, Invia e Non inviare. In base all'input, si indicherà agli arresti anomali di App Center cosa fare e l'arresto anomalo verrà quindi gestito di conseguenza.

Nota

L'SDK non visualizza una finestra di dialogo per questa operazione, l'app deve fornire la propria interfaccia utente per richiedere il consenso dell'utente.

Il metodo seguente illustra come configurare un gestore di conferma utente:

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

Nel caso in cui venga restituito YES/true nel blocco del gestore precedente, l'app deve ottenere l'autorizzazione utente e invitare l'SDK con il risultato usando l'API seguente. Se si usa un avviso per questo, come illustrato nell'esempio precedente, si chiamerà in base al risultato (ModalResponse) della runModal chiamata.

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

Abilitare l'rilevamento di eccezioni non eseguite generate nel thread principale

AppKit rileva le eccezioni generate nel thread principale, impedendo all'applicazione di arrestarsi in modo anomalo in macOS, in modo che l'SDK non possa rilevare questi arresti anomali. Per simulare il comportamento iOS, impostare NSApplicationCrashOnExceptions flag prima dell'inizializzazione dell'SDK, questo flag consente all'applicazione di arrestare l'arresto anomalo delle eccezioni non eseguite e l'SDK può segnalarli.

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

Nota

App Center SDK imposta automaticamente il flag nelle versioni 1.10.0 e successive. A partire dalla versione 1.11.0 questo flag non è più impostato automaticamente.

Disabilitare l'inoltro delle chiamate dei metodi della classe principale dell'applicazione agli arresti anomali di App Center

App Center Crashes SDK usa swizzling per migliorare la sua integrazione inoltrando anche alcune delle chiamate dei metodi della classe principale dell'applicazione. Il metodo swizzling è un modo per modificare l'implementazione dei metodi in fase di esecuzione. Se per qualsiasi motivo non si vuole usare il scorrimento a scorrimento (ad esempio a causa di criteri specifici), è necessario eseguire l'override dei metodi e sendEvent: dell'applicazione reportException: per consentire agli arresti anomali di segnalare correttamente le eccezioni generate nel thread principale.

  1. Creare il file ReportExceptionApplication.m e aggiungere l'implementazione seguente:

    @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
    

    Nota

    trycatch/Swift non funziona con NSException. Queste eccezioni possono essere gestite solo in Objective-C.

  2. Aprire il file Info.plist e sostituire NSApplication nel campo Classe Principal con il nome della classe applicazione , ReportExceptionApplication in questo esempio.

  3. Per disabilitare il swizzling in App Center SDK, aggiungere la AppCenterApplicationForwarderEnabled chiave al file Info.plist e impostare il valore su 0.

Ottenere informazioni sullo stato di invio per un log di arresto anomalo

A volte, si vuole conoscere lo stato dell'arresto anomalo dell'app. Un caso d'uso comune è che è possibile visualizzare l'interfaccia utente che indica agli utenti che l'app invia un report di arresto anomalo o, nel caso in cui l'app si arresta in modo anomalo rapidamente dopo l'avvio, si vuole modificare il comportamento dell'app per assicurarsi che i log di arresto anomalo possano essere inviati. Il CrashesDelegateprotocollo definisce tre callback diversi che è possibile usare nell'app per ricevere una notifica di ciò che succede:

Il callback seguente verrà richiamato prima che l'SDK invii un log di arresto anomalo

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

In caso di problemi di rete o interruzione nell'endpoint e riavvio dell'app, willSendErrorReport viene attivata nuovamente dopo il riavvio del processo.

Il callback seguente verrà richiamato dopo che l'SDK ha inviato correttamente un log di arresto anomalo

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

Il callback seguente verrà richiamato se l'SDK non è riuscito a inviare un log di arresto anomalo

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

La ricezione didFailSendingErrorReport indica un errore non recuperabile, ad esempio un codice 4xx . Ad esempio, 401 significa che l'errore appSecret è errato.

Questo callback non viene attivato se si tratta di un problema di rete. In questo caso, l'SDK continua a ripetere i tentativi (e sospende anche i tentativi mentre la connessione di rete è inattiva).

Aggiungere allegati a un report di arresto anomalo

È possibile aggiungere allegati binari e di testo a un report di arresto anomalo. L'SDK li invierà insieme all'arresto anomalo in modo da poterli visualizzare nel portale di App Center. Il callback seguente verrà richiamato subito prima di inviare l'arresto anomalo archiviato dall'avvio dell'applicazione precedente. Non verrà richiamato quando si verifica l'arresto anomalo. Ecco un esempio di come collegare il testo e un'immagine a un arresto anomalo:

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

Nota

Il limite di dimensioni è attualmente 7 MB. Il tentativo di inviare un allegato più grande attiverà un errore.

Abilitare o disabilitare gli arresti anomali di App Center in fase di esecuzione

È possibile abilitare e disabilitare gli arresti anomali del Centro app in fase di esecuzione. Se la disabilita, l'SDK non eseguirà alcuna segnalazione di arresto anomalo per l'app.

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

Per abilitare di nuovo gli arresti anomali di App Center, usare la stessa API ma passare YES/true come parametro.

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

Lo stato viene mantenuto nello spazio di archiviazione del dispositivo tra i lanci dell'applicazione.

Nota

Questo metodo deve essere usato solo dopo Crashes l'avvio.

Verificare se è abilitato l'arresto anomalo di App Center

È anche possibile verificare se gli arresti anomali di App Center sono abilitati o meno:

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

Nota

Questo metodo deve essere usato solo dopo Crashes l'avvio, verrà sempre restituito false prima dell'avvio.

Disabilitazione della gestione delle eccezioni di Mach

Per impostazione predefinita, App Center Arresti anomali usa il gestore eccezioni Mach per rilevare segnali irreversibili, ad esempio gli overflow dello stack, tramite un server di eccezioni Mach.

Il disableMachExceptionHandlermetodo -offre un'opzione per disabilitare l'individuazione dei segnali irreversibili tramite un server di eccezione Mach. Se si vuole disabilitare il gestore eccezioni Mach, è necessario chiamare questo metodo PRIMA di avviare l'SDK. Il codice di installazione tipico sarà simile al seguente:

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