Сбои Центра приложений (Android)

Важно!

Прекращение поддержки Центра приложений Visual Studio запланировано на 31 марта 2025 г. Хотя вы можете продолжать использовать Центр приложений Visual Studio до полного прекращения его использования, существует несколько рекомендуемых вариантов, на которые можно перейти.

Узнайте больше о сроках поддержки и альтернативных вариантах.

При сбоях Центра приложений автоматически создается журнал сбоев при каждом сбое приложения. Сначала журнал записывается в хранилище устройства, и когда пользователь снова запустит приложение, отчет о сбое будет отправлен в Центр приложений. Сбор сбоев работает как для бета-версии, так и для динамических приложений, т. е. тех, которые отправлены в Google Play. Журналы сбоев содержат ценные сведения, которые помогут устранить сбой.

Если вы еще не настроили пакет SDK в приложении, следуйте инструкциям в разделе начало работы.

Создание аварийного завершения теста

Сбои Центра приложений предоставляют API для создания тестового сбоя для простого тестирования пакета SDK. Этот API можно использовать только в отладочных сборках и не будет выполнять никаких действий в сборках выпуска.

Crashes.generateTestCrash();
Crashes.generateTestCrash()

Дополнительные сведения о предыдущем сбое

При сбоях Центра приложений есть два API, которые предоставляют дополнительные сведения на случай сбоя приложения.

Приложение получило предупреждение о нехватке памяти в предыдущем сеансе?

В любое время после запуска пакета SDK можно проверка, если приложение получило предупреждение о памяти в предыдущем сеансе:

Crashes.hasReceivedMemoryWarningInLastSession();
Crashes.hasReceivedMemoryWarningInLastSession()

Этот API является асинхронным. Дополнительные сведения см. в руководстве по асинхронным API Центра приложений .

Примечание

Этот метод следует использовать только после Crashes запуска. Он всегда возвращается false перед запуском.

Примечание

В некоторых случаях устройство с нехваткой памяти не может отправлять события.

Произошел сбой приложения в предыдущем сеансе?

В любой момент после запуска пакета SDK можно проверка, если приложение аварийно завершалось при предыдущем запуске:

Crashes.hasCrashedInLastSession();
Crashes.hasCrashedInLastSession()

Этот API является асинхронным. Дополнительные сведения см. в руководстве по асинхронным API Центра приложений .

Это удобно в случае, если вы хотите настроить поведение или пользовательский интерфейс приложения после сбоя. Некоторые разработчики решили показать дополнительный пользовательский интерфейс, чтобы извиниться перед пользователями, или хотят, чтобы связаться с ними после сбоя.

Примечание

Этот метод следует использовать только после Crashes запуска. Он всегда возвращается false перед запуском.

Сведения о последнем сбое

Если приложение ранее завершалось сбоем, вы можете получить сведения о последнем сбое.

Crashes.getLastSessionCrashReport();
Crashes.getLastSessionCrashReport()

Этот API является асинхронным. Дополнительные сведения см. в руководстве по асинхронным API Центра приложений .

Существует множество вариантов использования этого API. Наиболее распространенный из них — люди, которые вызывают этот API и реализуют свой пользовательский CrashesListener.

Примечание

Этот метод следует использовать только после Crashes запуска. Он всегда возвращается null перед запуском.

Настройка использования сбоев Центра приложений

Сбои Центра приложений предоставляют разработчикам обратные вызовы для выполнения дополнительных действий до и при отправке журналов сбоев в Центр приложений.

Для обработки обратных вызовов либо реализуйте все методы в CrashesListener интерфейсе, либо переопределите AbstractCrashesListener класс и выберите только те, которые вас интересуют.

Использование собственного CrashesListener

Создайте собственный CrashesListener и назначьте его следующим образом:

CrashesListener customListener = new CrashesListener() {
    // Implement all callbacks here.
};
Crashes.setListener(customListener);
val customListener = object : CrashesListener {
    // Implement all callbacks here.
}
Crashes.setListener(customListener)

Если вы заинтересованы только в настройке некоторых обратных вызовов, используйте AbstractCrashesListener вместо этого:

AbstractCrashesListener customListener = new AbstractCrashesListener() {
    // Implement any callback here as required.
};
Crashes.setListener(customListener);
val customListener = object : AbstractCrashesListener() {
    // Implement any callback here as required.
}
Crashes.setListener(customListener)

Примечание

Настройте прослушиватель перед вызовом AppCenter.start(), так как центр приложений начинает обработку сразу после запуска.

Следует ли обработать сбой?

Реализуйте этот обратный вызов, если вы хотите решить, нужно ли обрабатывать конкретный сбой. Например, может произойти сбой на уровне системы, который вы хотите игнорировать и не хотите отправлять в Центр приложений.

@Override
public boolean shouldProcess(ErrorReport report) {
    return true; // return true if the crash report should be processed, otherwise false.
}
override fun shouldProcess(report: ErrorReport?): Boolean {
    return true
}

Если для вас важна конфиденциальность пользователей, вы можете получить подтверждение пользователя перед отправкой отчета о сбоях в Центр приложений. Пакет SDK предоставляет обратный вызов, который сообщает о сбоях Центра приложений о том, что перед отправкой отчетов о сбоях пользователь ожидает подтверждения.

Если вы решили сделать это, вы несете ответственность за получение подтверждения пользователя, например через диалоговое окно с одним из следующих вариантов: Всегда отправлять, Отправлять и Не отправлять. В зависимости от входных данных вы укаживаете, что нужно сделать, и сбой будет обрабатываться соответствующим образом.

Примечание

Пакет SDK не отображает диалоговое окно для этого, приложение должно предоставить собственный пользовательский интерфейс для запроса согласия пользователя.

В следующем обратном вызове показано, как сообщить пакету SDK о необходимости дождаться подтверждения пользователя перед отправкой сбоев.

@Override
public boolean shouldAwaitUserConfirmation() {

    // Build your own UI to ask for user consent here. SDK doesn't provide one by default.

    // Return true if you built a UI for user consent and are waiting for user input on that custom UI, otherwise false.
    return true;
}
override fun shouldAwaitUserConfirmation(): Boolean {
    return true
}

Если вы возвращаете trueзначение , приложение должно получить (с помощью собственного кода) разрешение пользователя и предоставить пакет SDK с результатом с помощью следующего API:

// Depending on the user's choice, call Crashes.notifyUserConfirmation() with the right value.
Crashes.notifyUserConfirmation(Crashes.DONT_SEND);
Crashes.notifyUserConfirmation(Crashes.SEND);
Crashes.notifyUserConfirmation(Crashes.ALWAYS_SEND);
Crashes.notifyUserConfirmation(Crashes.DONT_SEND)
Crashes.notifyUserConfirmation(Crashes.SEND)
Crashes.notifyUserConfirmation(Crashes.ALWAYS_SEND)

В качестве примера можно обратиться к нашему примеру настраиваемого диалога.

Получение сведений о состоянии отправки для журнала сбоев

Иногда требуется узнать состояние сбоя приложения. Распространенный вариант использования заключается в том, что может потребоваться показать пользовательский интерфейс, который сообщает пользователям, что приложение отправляет отчет о сбоях, или, если приложение быстро аварийно завершает работу после запуска, необходимо настроить поведение приложения, чтобы убедиться, что журналы сбоев можно отправить. При сбоях Центра приложений есть три разных обратных вызова, которые можно использовать в приложении для уведомления о том, что происходит:

Следующий обратный вызов будет вызван до того, как пакет SDK отправит журнал сбоев

@Override
public void onBeforeSending(ErrorReport errorReport) {
    // Your code, e.g. to present a custom UI.
}
override fun onBeforeSending(report: ErrorReport?) {
    // Your code, e.g. to present a custom UI.
}

Если у нас есть проблемы с сетью или сбой в конечной точке, и вы перезапустите приложение, onBeforeSending активируется снова после перезапуска процесса.

Следующий обратный вызов будет вызван после успешной отправки пакета SDK журнала сбоев.

@Override
public void onSendingSucceeded(ErrorReport report) {
    // Your code, e.g. to hide the custom UI.
}
override fun onSendingSucceeded(report: ErrorReport?) {
    // Your code, e.g. to hide the custom UI.
}

Следующий обратный вызов будет вызываться, если пакету SDK не удалось отправить журнал сбоев

@Override
public void onSendingFailed(ErrorReport report, Exception e) {
    // Your code goes here.
}
override fun onSendingFailed(report: ErrorReport?, e: Exception?) {
    // Your code goes here.
}

Получение onSendingFailed означает, что произошла невосстановимая ошибка, например код 4xx . Например, 401 означает, что appSecret неправильно.

Этот обратный вызов не активируется, если это проблема с сетью. В этом случае пакет SDK продолжает повторять попытки (а также приостанавливает повторные попытки, пока сетевое подключение не работает).

Добавление вложений в отчет о сбоях

В отчет о сбое можно добавлять двоичные и текстовые вложения. Пакет SDK отправит их вместе со сбоем, чтобы их можно было увидеть на портале Центра приложений. Следующий обратный вызов будет вызван непосредственно перед отправкой сохраненного сбоя из предыдущих запусков приложения. Он не будет вызываться при сбое. Убедитесь, что файл вложения не имеет имени minidump.dmp , так как это имя зарезервировано для файлов minidump. Ниже приведен пример присоединения текста и изображения к аварийному завершению.

@Override
public Iterable<ErrorAttachmentLog> getErrorAttachments(ErrorReport report) {

    // Attach some text.
    ErrorAttachmentLog textLog = ErrorAttachmentLog.attachmentWithText("This is a text attachment.", "text.txt");

    // Attach binary data.
    byte[] binaryData = getYourBinary();
    ErrorAttachmentLog binaryLog = ErrorAttachmentLog.attachmentWithBinary(binaryData, "your_filename.jpeg", "image/jpeg");

    // Return attachments as list.
    return Arrays.asList(textLog, binaryLog);
}
override fun getErrorAttachments(report: ErrorReport?): MutableIterable<ErrorAttachmentLog> {

    // Attach some text.
    val textLog = ErrorAttachmentLog.attachmentWithText("This is a text attachment.", "text.txt")

    // Attach binary data.
    val binaryData = getYourBinary()
    val binaryLog = ErrorAttachmentLog.attachmentWithBinary(binaryData, "your_filename.jpeg", "image/jpeg")

    // Return attachments as list.
    return listOf(textLog, binaryLog)
}

Примечание

В настоящее время максимальный размер составляет 7 МБ. Попытка отправить вложение большего размера вызовет ошибку.

Включение или отключение сбоев Центра приложений во время выполнения

Вы можете включить и отключить сбои Центра приложений во время выполнения. Если вы отключите его, пакет SDK не будет сообщать о сбоях для приложения.

Crashes.setEnabled(false);
Crashes.setEnabled(false)

Чтобы снова включить сбои Центра приложений, используйте тот же API, но передайте true в качестве параметра.

Crashes.setEnabled(true);
Crashes.setEnabled(true)

Состояние сохраняется в хранилище устройства при запусках приложений.

Этот API является асинхронным. Дополнительные сведения см. в руководстве по асинхронным API Центра приложений .

Примечание

Этот метод следует использовать только после Crashes запуска.

Проверьте, включены ли сбои Центра приложений

Вы также можете проверка, включены ли сбои Центра приложений:

Crashes.isEnabled();
Crashes.isEnabled()

Этот API является асинхронным. Дополнительные сведения см. в руководстве по асинхронным API Центра приложений .

Примечание

Этот метод следует использовать только после Crashes запуска. Он всегда возвращается false перед запуском.

Обработано ошибок

Центр приложений также позволяет отслеживать ошибки с помощью обрабатываемых исключений. Для этого используйте trackError метод :

try {
    // your code goes here.
} catch (Exception exception) {
    Crashes.trackError(exception);
}
try {
    // your code goes here.
} catch (exception: Exception) {
    Crashes.trackError(exception)
}

При необходимости приложение может прикрепить свойства к обработанной ошибке для предоставления дополнительного контекста. Передайте свойства в виде карты пар "ключ-значение" (только строки), как показано в примере ниже.

try {
    // your code goes here.
} catch (Exception exception) {
    Map<String, String> properties = new HashMap<String, String>() {{
        put("Category", "Music");
        put("Wifi", "On");
    }};
    Crashes.trackError(exception, properties, null);
}
try {
    // your code goes here.
} catch (exception: Exception) {
    val properties = mapOf("Category" to "Music", "Wifi" to "On")
    Crashes.trackError(exception, properties, null)
}

Кроме того, при необходимости можно добавить двоичные и текстовые вложения в отчет об ошибках. Передайте вложения в виде , Iterable как показано в примере ниже.

try {
    // your code goes here.
} catch (Exception exception) {

    // Attach some text.
    ErrorAttachmentLog textLog = ErrorAttachmentLog.attachmentWithText("This is a text attachment.", "text.txt");

    // Attach binary data.
    byte[] binaryData = getYourBinary();
    ErrorAttachmentLog binaryLog = ErrorAttachmentLog.attachmentWithBinary(binaryData, "your_filename.jpeg", "image/jpeg");

    // Track an exception with attachments.
    Crashes.trackError(exception, null, Arrays.asList(textLog, binaryLog));
}
try {
    // your code goes here.
} catch (exception: Exception) {

    // Attach some text.
    val textLog = ErrorAttachmentLog.attachmentWithText("This is a text attachment.", "text.txt")

    // Attach binary data.
    val binaryData = getYourBinary()
    val binaryLog = ErrorAttachmentLog.attachmentWithBinary(binaryData, "your_filename.jpeg", "image/jpeg")

    // Track an exception with attachments.
    Crashes.trackError(exception, null, listOf(textLog, binaryLog))
}

Отчеты о сбое NDK

Создание отчетов о сбоях

Чтобы получить правильные отчеты о сбоях в Центре приложений, сначала убедитесь, что у вас есть пакет SDK для аварийного завершения работы Центра приложений, выполнив приведенные выше инструкции.

Создание библиотеки брейк-панели

Затем включите и скомпилируйте Google Breakpad, следуя инструкциям, перечисленным в официальном google Breakpad для Android README.

Примечание

Пакет SDK центра приложений по умолчанию не объединяет Google Breakpad.

Присоединение обработчика исключений

После включения Google Breakpad подключите обработчик сбоя NDK после AppCenter.start:

// Attach NDK Crash Handler after SDK is initialized.
Crashes.getMinidumpDirectory().thenAccept(new AppCenterConsumer<String>() {
    @Override
    public void accept(String path) {

        // Path is null when Crashes is disabled.
        if (path != null) {
            setupNativeCrashesListener(path);
        }
    }
});

Метод setupNativeCrashesListener является собственным методом, который необходимо реализовать в C/C++:

#include "google-breakpad/src/client/linux/handler/exception_handler.h"
#include "google-breakpad/src/client/linux/handler/minidump_descriptor.h"

void Java_com_microsoft_your_package_YourActivity_setupNativeCrashesListener(
        JNIEnv *env, jobject, jstring path) {
    const char *dumpPath = (char *) env->GetStringUTFChars(path, NULL);
    google_breakpad::MinidumpDescriptor descriptor(dumpPath);
    new google_breakpad::ExceptionHandler(descriptor, NULL, dumpCallback, NULL, true, -1);
    env->ReleaseStringUTFChars(path, dumpPath);
}

Где dumpCallback используется для устранения неполадок:

/*
 * Triggered automatically after an attempt to write a minidump file to the breakpad folder.
 */
bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
                  void *context,
                  bool succeeded) {

    // Allow system to log the native stack trace.
    __android_log_print(ANDROID_LOG_INFO, "YourLogTag",
                        "Wrote breakpad minidump at %s succeeded=%d\n", descriptor.path(),
                        succeeded);
    return false;
}

После правильной настройки этих методов приложение автоматически отправляет минидамп в Центр приложений после перезапуска. Для устранения неполадок можно использовать подробные журналы (AppCenter.setLogLevel(Log.VERBOSE) до AppCenter.start) для проверка отправки минидампов после перезапуска приложения.

Примечание

Центр приложений использует зарезервированное имя minidump.dmp для вложений минидампа. Обязательно присвойте вложениям другое имя, если это не минидамп-файл, чтобы мы могли правильно обрабатывать его.

Примечание

Существует известная ошибка в брейк-панели, которая делает невозможным запись сбоев в эмуляторах x86.

Символика

Дополнительные сведения об обработке сбоев см. в документации по диагностике .