Сбои Центра приложений (iOS)
Важно!
Прекращение поддержки Центра приложений Visual Studio запланировано на 31 марта 2025 г. Хотя вы можете продолжать использовать Центр приложений Visual Studio, пока он не будет полностью выведен из эксплуатации, существует несколько рекомендуемых вариантов, на которые вы можете рассмотреть возможность миграции.
Узнайте больше о сроках поддержки и альтернативных вариантах.
Сбои Центра приложений автоматически создают журнал сбоев при каждом сбое приложения. Журнал сначала записывается в хранилище устройства, и когда пользователь снова запустит приложение, отчет о сбоях будет отправлен в Центр приложений. Сбор сбоев работает как для бета-, так и для динамических приложений, т. е. для приложений, отправленных в App Store. Журналы сбоев содержат ценные сведения, которые помогут устранить сбои.
Если вы еще не настроили пакет SDK в приложении, следуйте инструкциям в разделе начало работы.
Кроме того, журналы сбоев в iOS требуют символики, проверка из документации по диагностике Центра приложений, в которых объясняется, как предоставить символы для приложения.
Примечание
Пакет SDK не будет пересылать журнал сбоев, если вы подключены к отладчику. Убедитесь, что отладчик не подключен при сбое приложения.
Примечание
Чтобы получить правильно символические трассировки стека, убедитесь, что бит-код отключен. Дополнительные сведения о бит-коде см. в документации по символике iOS в Центре приложений.
Примечание
4.0.0
В версии Центра приложений были введены критические изменения. Чтобы перенести Центр приложений с предыдущих версий, следуйте инструкциям в разделе Миграция в пакет SDK для Центра приложений 4.0.0 и более поздних версий.
Центр приложений поддерживает отчеты о сбоях в расширениях iOS. Использование такое же, как и в контейнерном приложении.
Сбои Центра приложений предоставляют API для создания тестового сбоя для простого тестирования пакета SDK. Этот API можно использовать только в тестовых или бета-версиях приложений и не будет выполнять никаких действий в рабочих приложениях.
[MSACCrashes generateTestCrash];
Crashes.generateTestCrash()
При сбоях центра приложений есть два API, которые предоставляют дополнительные сведения на случай сбоя приложения.
В любой момент после запуска пакета SDK можно проверка, если приложение получило предупреждение о памяти в предыдущем сеансе:
[MSACCrashes hasReceivedMemoryWarningInLastSession];
Crashes.hasReceivedMemoryWarningInLastSession
Примечание
Этот метод следует использовать только после Crashes
запуска, он всегда будет возвращать NO
или false
до запуска.
Примечание
В некоторых случаях устройство с низким объемом памяти не может отправлять события.
В любой момент после запуска пакета SDK можно проверка, если приложение не произошло при предыдущем запуске:
[MSACCrashes hasCrashedInLastSession];
Crashes.hasCrashedInLastSession
Это удобно, если вы хотите настроить поведение или пользовательский интерфейс приложения после сбоя.
Примечание
Этот метод следует использовать только после MSACCrashes
запуска, он всегда будет возвращать NO
или false
до запуска.
Если приложение ранее завершалось сбоем, вы можете получить сведения о последнем сбое.
MSACErrorReport *crashReport = [MSACCrashes lastSessionCrashReport];
var crashReport = Crashes.lastSessionCrashReport
Примечание
Этот метод следует использовать только после Crashes
запуска. Он всегда возвращается nil
перед запуском.
Существует множество вариантов использования этого API. Наиболее распространенными являются люди, которые вызывают этот API и реализуют свои пользовательские CrashesDelegate.
Сбои Центра приложений предоставляют разработчикам обратные вызовы для выполнения дополнительных действий до и при отправке журналов сбоев в Центр приложений.
Чтобы добавить пользовательское поведение, необходимо внедрить CrashesDelegate
протокол -protocol, все его методы являются необязательными.
[MSACCrashes setDelegate:self];
Crashes.delegate = self
Примечание
Необходимо задать делегат перед вызовом AppCenter.start
, так как центр приложений запускает обработку сразу после запуска.
crashes:shouldProcessErrorReport:
Реализуйте -method в классе , который принимает CrashesDelegate
протокол ,если вы хотите решить, нужно ли обрабатывать конкретный сбой. Например, может произойти сбой на уровне системы, который вы хотите игнорировать и не хотите отправлять в Центр приложений.
- (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.
}
Центр приложений также позволяет отслеживать ошибки с помощью обрабатываемых исключений с помощью 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)
}
Если конфиденциальность пользователей важна для вас, вы можете получить подтверждение пользователя перед отправкой отчета о сбое в Центр приложений. Пакет SDK предоставляет обратный вызов, который сообщает о сбоях Центра приложений о том, что ожидает подтверждения пользователя перед отправкой отчетов о сбоях.
Если вы решили сделать это, вы несете ответственность за получение подтверждения пользователя, например с помощью диалогового запроса с одним из следующих вариантов: Всегда отправлять, Отправлять и Не отправлять. В зависимости от входных данных вы сообщите Центру приложений, что делать, а затем будет обработано соответствующим образом.
Примечание
Пакет SDK не отображает диалоговое окно для этого, приложение должно предоставить собственный пользовательский интерфейс, чтобы запросить согласие пользователя.
Примечание
Приложение не должно вызывать notifyWithUserConfirmation
явным образом, если оно не реализует диалоговое окно подтверждения пользователя. Модуль Аварийное завершение будет обрабатывать отправку журналов для вас неявно.
Следующий метод показывает, как настроить обработчик подтверждения пользователя:
[MSACCrashes setUserConfirmationHandler:(^(NSArray<MSACErrorReport *> *errorReports) {
// Your code to present your UI to the user, e.g. an UIAlertController.
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:@"Sorry about that!"
message:@"Do you want to send an anonymous crash report so we can fix the issue?"
preferredStyle:UIAlertControllerStyleAlert];
[alertController
addAction:[UIAlertAction actionWithTitle:@"Don't send"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
[MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationDontSend];
}]];
[alertController
addAction:[UIAlertAction actionWithTitle:@"Send"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationSend];
}]];
[alertController
addAction:[UIAlertAction actionWithTitle:@"Always send"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[MSACCrashes notifyWithUserConfirmation:MSACUserConfirmationAlways];
}]];
// Show the alert controller.
[self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
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 UIAlertController.
let alertController = UIAlertController(title: "Sorry about that!",
message: "Do you want to send an anonymous crash report so we can fix the issue?",
preferredStyle:.alert)
alertController.addAction(UIAlertAction(title: "Don't send", style: .cancel) {_ in
Crashes.notify(with: .dontSend)
})
alertController.addAction(UIAlertAction(title: "Send", style: .default) {_ in
Crashes.notify(with: .send)
})
alertController.addAction(UIAlertAction(title: "Always send", style: .default) {_ in
Crashes.notify(with: .always)
})
// Show the alert controller.
self.window?.rootViewController?.present(alertController, animated: true)
return true // Return true if the SDK should await user confirmation, otherwise return false.
})
Если вы вернелись YES
/true
в блок обработчика выше, приложение должно получить разрешение пользователя и предоставить пакету SDK с результатом с помощью следующего API. Если вы используете для этого оповещение, как в приведенном выше примере, вы будете вызывать его из реализации обратного alertView:clickedButtonAtIndex:
вызова -.
// Depending on the users'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)
Иногда требуется узнать состояние сбоя приложения. Распространенный вариант использования заключается в том, что может потребоваться показать пользовательский интерфейс, который сообщает пользователям, что приложение отправляет отчет о сбое, или, если приложение быстро завершается сбоем после запуска, необходимо настроить поведение приложения, чтобы убедиться, что журналы сбоев можно отправить. Протокол CrashesDelegate
-определяет три разных обратных вызова, которые можно использовать в приложении для уведомления о том, что происходит:
- (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
активируется снова после перезапуска процесса.
- (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.
}
- (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 отправит их вместе с аварийным завершением, чтобы их можно было увидеть на портале Центра приложений. Следующий обратный вызов будет вызываться непосредственно перед отправкой сохраненного сбоя из предыдущих запусков приложений. Он не будет вызываться при сбое. Ниже приведен пример вложения текста и изображения в сбой:
- (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 МБ. Попытка отправить вложение большего размера вызовет ошибку.
Вы можете включить и отключить сбои Центра приложений во время выполнения. Если вы отключите его, пакет SDK не будет сообщать о сбоях для приложения.
[MSACCrashes setEnabled:NO];
Crashes.enabled = false
Чтобы снова включить сбои Центра приложений, используйте тот же API, но передайте YES
/true
в качестве параметра.
[MSACCrashes setEnabled:YES];
Crashes.enabled = true
Состояние сохраняется в хранилище устройства при запусках приложений.
Примечание
Этот метод следует использовать только после Crashes
запуска.
Вы также можете проверка, включены ли сбои Центра приложений:
BOOL enabled = [MSACCrashes isEnabled];
var enabled = Crashes.enabled
Примечание
Этот метод следует использовать только после Crashes
запуска. Он всегда возвращается false
перед запуском.
По умолчанию сбои Центра приложений используют обработчик исключений Mach для перехвата неустранимых сигналов, например переполнения стека, через сервер исключений Mach.
Метод disableMachExceptionHandler
-предоставляет возможность отключить перехват неустранимых сигналов через сервер исключений 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])