App Center 崩溃 (Android)

重要

Visual Studio App Center 于 2025 年 3 月 31 日停用,但分析和诊断功能除外,这些功能将继续受支持,直到 2026 年 6 月 30 日。 了解详细信息

每次应用发生崩溃时,App Center Crashes 功能都会自动生成一份崩溃日志。 日志首先写入设备的存储,当用户再次启动应用时,崩溃报告将发送到 App Center。 收集崩溃报告适用于 beta 版本和已上线的应用,即那些已提交到 Google Play 的应用。 故障日志包含有助于修复崩溃的重要信息。

如果尚未在应用程序中设置 SDK,请按照 “入门 ”部分进行作。

触发测试崩溃

App Center 的崩溃模块提供了一个 API,用于生成测试崩溃,以方便测试 SDK。 此 API 只能在调试版本中使用,并且不会在发布版本中执行任何作。

Crashes.generateTestCrash();
Crashes.generateTestCrash()

获取有关以前崩溃的详细信息

App Center 崩溃功能提供两个 API,当应用程序崩溃时为您提供更多信息。

应用在上一个会话中是否收到内存不足的警告?

启动 SDK 后,可以随时检查应用是否在上一会话中收到内存警告:

Crashes.hasReceivedMemoryWarningInLastSession();
Crashes.hasReceivedMemoryWarningInLastSession()

此 API 是异步的,可以在 App Center 异步 API 指南中详细了解该 API。

注释

此方法应仅在 Crashes 启动后使用,在启动前,它将始终返回 false

注释

在某些情况下,内存不足的设备无法发送事件。

应用在上一个会话中是否崩溃?

启动 SDK 后,可以随时检查应用是否在上一次启动中崩溃:

Crashes.hasCrashedInLastSession();
Crashes.hasCrashedInLastSession()

此 API 是异步的,可以在 App Center 异步 API 指南中详细了解该 API。

如果想要在发生崩溃后调整应用的行为或 UI,这非常有用。 一些开发人员选择显示额外的用户界面来向用户道歉,或者希望在应用崩溃后找到一种与用户联系的方法。

注释

此方法应仅在 Crashes 启动后使用,在启动前,它将始终返回 false

有关上次崩溃的详细信息

如果应用之前崩溃,可以获取有关上次崩溃的详细信息。

Crashes.getLastSessionCrashReport();
Crashes.getLastSessionCrashReport()

此 API 是异步的,可以在 App Center 异步 API 指南中详细了解该 API。

此 API 有许多用例,最常见的用例是调用此 API 并实现其自定义 CrashesListener 的人员。

注释

此方法应仅在 Crashes 启动后使用,在启动前,它将始终返回 null

自定义 App Center 崩溃功能的使用

App Center 崩溃为开发人员提供回调,以便在崩溃日志发送到 App Center 之前和时执行其他操作。

若要处理回调,请实现接口中的所有 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()设置侦听器,因为 App Center 在启动后立即开始处理崩溃。

是否应处理故障?

如果您希望决定某个特定崩溃是否需要处理,请实现此回调。 例如,系统级崩溃您可能希望忽略,并且您不想发送到 App Center。

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

如果用户隐私对你很重要,你可能希望在将崩溃报告发送到 App Center 之前获取用户确认。 SDK 公开了一个回调接口,指示 App Center 崩溃在发送崩溃报告之前等待用户确认。

如果选择这样做,则需负责获取用户的确认,例如,通过具有以下选项之一的对话框提示: 始终发送发送不发送。 根据提供的输入,你将告知 App Center 崩溃要执行什么操作,然后会相应地处理崩溃。

注释

SDK 不为此显示对话框,应用必须提供自己的 UI 才能请求用户同意。

以下回调演示如何告知 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,你的应用必须获取用户的权限(使用自己的代码),并使用以下 API 向 SDK 发送结果消息:

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

例如,可以参考 我们的自定义对话示例

获取有关故障日志的发送状态的信息

有时,你想知道应用崩溃的状态。 常见的用例是,你可能想要显示 UI,告知用户你的应用正在提交崩溃报告,或者,如果应用在启动后快速崩溃,你想要调整应用的行为,以确保可以提交崩溃日志。 App Center 崩溃服务提供三个不同的回调函数,您可以在应用中使用这些回调来接收有关事件情况的通知。

在 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 会随崩溃一起发送它们,以便在 App Center 门户中看到它们。 在发送之前的应用程序启动时存储的崩溃之前,将立即调用以下回调。 崩溃发生时不会调用它。 请确保附件文件 命名为 minidump.dmp,因为该名称是保留给小型转储文件的。 下面是如何在崩溃报告中附加文本和图像的示例:

@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 MB。 尝试发送更大的附件将触发错误。

在运行时启用或禁用 App Center 崩溃功能

可以在运行时启用或禁用 App Center 崩溃功能。 如果禁用它,SDK 不会针对应用执行任何崩溃报告。

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

若要再次启用 App Center Crashes,请使用相同的 API,但将 true 作为参数传递。

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

状态在应用程序启动时保留在设备的存储中。

此 API 是异步的,可以在 App Center 异步 API 指南中详细了解该 API。

注释

此方法只能在启动 Crashes 后使用。

检查是否启用了 App Center 崩溃功能

您还可以检查 App Center 的崩溃报告功能是否已启用:

Crashes.isEnabled();
Crashes.isEnabled()

此 API 是异步的,可以在 App Center 异步 API 指南中详细了解该 API。

注释

此方法应仅在 Crashes 启动后使用,在启动前,它将始终返回 false

已处理的错误

App Center 还允许使用已处理的异常来跟踪错误。 为此,请使用 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 崩溃

报告崩溃

若要在 App Center 中接收适当的故障报告,请先按照上面列出的说明确保已设置 App Center 崩溃 SDK。

构建Breakpad库

接下来,按照官方 Google Breakpad for Android 自述文件中列出的说明,包括并编译 Google Breakpad。

注释

默认情况下,App Center SDK 不会捆绑 Google Breakpad。

附加异常处理程序

包括 Google Breakpad 后,在AppCenter.start之后附加 NDK 崩溃处理程序。

// 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;
}

正确设置这些方法后,应用重启后会自动将小型转储发送到 App Center。 若要进行故障排除,可以使用详细日志(AppCenter.setLogLevel(Log.VERBOSE) 之前 AppCenter.start)检查应用重启后是否发送了小型转储。

注释

App Center 使用迷你转储附件的保留名称 minidump.dmp 。 请确保为附件提供其他名称,除非它是小型转储文件,以便我们可以正确处理它。

注释

已知 Breakpad 中存在一个 bug,这导致无法在 x86 模拟器上捕获崩溃。

符号

有关崩溃处理的详细信息,请参阅 诊断文档