Поделиться через


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

Это важно

Центр приложений Visual Studio был прекращен 31 марта 2025 г., за исключением функций аналитики и диагностики, которые будут поддерживаться до 30 июня 2026 г. Подробнее.

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

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

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

App Center Crashes предоставляет API для генерации тестового сбоя, что упрощает тестирование пакета SDK. Этот API можно использовать только в отладочных сборках и ничего не делает в выпускных сборках.

Crashes.generateTestCrash();
Crashes.generateTestCrash()

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

App Center Crashes предоставляет два 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 до запуска.

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

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

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

Используйте собственный слушатель сбоев

Создайте собственный 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 предоставляет обратный вызов, который сообщает Центру приложений Crashes ожидать подтверждения от пользователя перед отправкой отчетов о сбоях.

Если вы решили сделать это, вы несете ответственность за получение подтверждения пользователя, например с помощью диалогового окна с одним из следующих параметров: Always Send, Send и Don't send. На основе входных данных вы сообщите App Center Crashes, что делать, и аварийное завершение работы будет обрабатываться соответствующим образом.

Замечание

Пакет 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)

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

Получите информацию о статусе отправки для журнала сбоев

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

Функция обратного вызова будет вызвана перед тем, как 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 так, как это имя зарезервировано для мини-dump-файлов. Ниже приведен пример подключения текста и изображения к сбою:

@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 МБ. Попытка отправить большее вложение приведет к ошибке.

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

Вы можете включать и отключать App Center Crashes в процессе работы. Если отключить его, пакет 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 для Центра приложений настроен, следуя приведенным выше инструкциям.

Создание библиотеки breakpad

Затем включите и скомпилируйте 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;
}

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

Замечание

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

Замечание

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

Символика

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