App Center (Android) 崩溃
重要
Visual Studio App Center 计划于 2025 年 3 月 31 日停用。 虽然可以继续使用 Visual Studio App Center,直到它完全停用,但你可以考虑迁移到几个建议的替代方法。
每次应用崩溃时,App Center 崩溃都会自动生成崩溃日志。 日志首先写入设备的存储,当用户再次启动应用时,故障报告将发送到 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,这将派上用场。 一些开发人员选择显示其他 UI 以向用户道歉,或者希望在崩溃发生后取得联系。
注意
此方法只能在启动后 Crashes
使用,它将始终在启动之前返回 false
。
有关上次崩溃的详细信息
如果你的应用以前崩溃,你可以获取有关上次崩溃的详细信息。
Crashes.getLastSessionCrashReport();
Crashes.getLastSessionCrashReport()
此 API 是异步的,可以在 App Center 异步 API 指南中详细了解此 API。
此 API 有许多用例,最常见的用例是调用此 API 并实现其自定义 CrashesListener 的人员。
注意
此方法只能在启动后 Crashes
使用,它将始终在启动之前返回 null
。
自定义 App Center 崩溃的使用情况
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 崩溃,请使用同一 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。
生成分隔板库
接下来,按照适用于 Android 的 Google Breakpad 官方自述文件中列出的说明,包括和编译 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
使用详细日志 (,以检查应用重启后是否发送了最小umps。
注意
App Center 使用小型转储附件的保留名称 minidump.dmp
。 请确保为附件指定其他名称,除非它是一个小型转储文件,以便我们可以正确处理它。
注意
断板中存在一个已知 bug,这使得无法在 x86 模拟器上捕获崩溃。
符号化
有关崩溃处理的详细信息,请参阅 诊断文档 。