App Center (Unity) 崩溃

重要

Visual Studio App Center 计划于 2025 年 3 月 31 日停用。 虽然可以继续使用 Visual Studio App Center,直到它完全停用,但你可以考虑迁移到几个建议的替代方法。

详细了解支持时间线和替代方法。

每次应用崩溃时,App Center 崩溃都会自动生成崩溃日志,并记录到设备存储。 当用户再次启动应用时,SDK 会将故障报告发送到 App Center。 收集崩溃适用于 beta 应用和实时应用,即提交到 Google Play 的崩溃。 故障日志包含有助于修复崩溃的重要信息。

如果尚未在应用程序中设置 SDK,请按照 Unity 入门 部分中的说明进行操作。

iOS 上的崩溃日志需要符号化。 若要启用符号化,请参阅 App Center 诊断文档,其中介绍了如何为应用提供符号。

重要

适用于 Unity 的崩溃 SDK 不支持 UWP。 本页中的说明仅涵盖 Android 和 iOS。

注意

如果附加了调试器,SDK 不会转发任何故障日志。 确保应用崩溃时未附加调试器。

注意

如果已在 Enable CrashReport APIPlayerSettings 中启用,则 SDK 不会收集故障日志。

生成测试崩溃

App Center 崩溃提供了一个 API,用于生成测试崩溃,以便轻松测试 SDK。 此 API 检查调试配置与发布配置。 因此,只能在调试时使用它,因为它不适用于发布应用。

Crashes.GenerateTestCrash();

注意

此方法仅适用于打开 的“开发生成” 设置。

获取有关上一次故障的详细信息

App Center 崩溃有两个 API,可在应用崩溃时为你提供详细信息。

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

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

bool hadLowMemoryWarning = Crashes.HasReceivedMemoryWarningInLastSessionAsync().Result;

注意

此方法在 中 Awake()不起作用。

注意

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

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

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

bool didAppCrash = await Crashes.HasCrashedInLastSessionAsync();

如果要在崩溃后调整应用的行为或 UI,调用 HasCrashedInLastSessionAsync 将很有用。 某些开发人员显示其他 UI 以向用户道歉,或者希望在发生崩溃后取得联系。

有关上次崩溃的详细信息

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

ErrorReport crashReport = await Crashes.GetLastSessionCrashReportAsync();

此 API 最常见的用例是在用户实现其自定义 崩溃委托或侦听器时。

自定义 App Center 崩溃的使用情况

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

注意

在 App Center 启动 之前 设置回调,例如在 方法中 Awake ,因为 App Center 在启动后立即开始处理崩溃。

是否应处理崩溃?

如果要确定是否需要处理特定崩溃,请设置以下回调。 例如,可能存在想要忽略且不发送到 App Center 的系统级崩溃。

Crashes.ShouldProcessErrorReport = (ErrorReport report) =>
{
     // Check the report in here and return true or false depending on the ErrorReport.
    return true;
};

如果用户隐私对你很重要,你可能希望在向 App Center 发送故障报告之前获得用户确认。 SDK 公开一个回调,告知 App Center 崩溃在发送任何崩溃报告之前等待用户确认。

如果代码使用此回调,则你负责获取用户的确认。 一个选项是通过对话框提示,其中包含以下选项之一: 始终发送发送不发送。 根据输入,你将告诉 App Center 崩溃要执行的操作,然后会相应地处理崩溃。

注意

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

以下回调演示如何告诉 SDK 在发送崩溃之前等待用户确认:

Crashes.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;
};

如果回调返回 true,则必须获取用户权限,并使用以下 API 向 SDK 发送结果消息:

// Depending on the user's choice, call Crashes.NotifyUserConfirmation() with the right value.
Crashes.NotifyUserConfirmation(UserConfirmation.DontSend);
Crashes.NotifyUserConfirmation(UserConfirmation.Send);
Crashes.NotifyUserConfirmation(UserConfirmation.AlwaysSend);

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

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

有时,你想知道应用崩溃的状态。 一个常见用例是显示一个 UI,通知用户应用正在提交崩溃报告。 另一种情况是,你想要调整应用的行为,以确保故障日志可以在重新启动后不久提交。 App Center 崩溃提供了三种不同的回调,你可以进行这些回调,以便收到所发生情况的通知:

在 SDK 发送崩溃日志之前,将调用以下回调

Crashes.SendingErrorReport += (errorReport) =>
{
    // Your code, e.g. to present a custom UI.
};

如果我们在终结点上遇到网络问题或中断,并且你重新启动应用, SendingErrorReport 则会在进程重启后再次触发。

SDK 成功发送崩溃日志后,将调用以下回调

Crashes.SentErrorReport += (errorReport) =>
{
    // Your code, e.g. to hide the custom UI.
};

如果 SDK 无法发送故障日志,将调用以下回调

Crashes.FailedToSendErrorReport += (errorReport, exception) =>
{
    // Your code goes here.
};

接收 FailedToSendErrorReport 意味着发生了不可恢复的错误,例如 4xx 代码。 例如, 401 表示 appSecret 错误。

如果这是网络问题,则不会触发此回调。 在这种情况下,SDK 会继续重试 (,并在网络连接关闭) 时暂停重试。

向崩溃或未经处理的异常报告添加附件

还可以选择将二进制和文本附件添加到崩溃或 未经处理的异常 报告。 SDK 将随报表一起发送它们,以便你可以在 App Center 门户中查看它们。 在发送存储的报告之前,将立即调用以下回调。 对于崩溃,它会在下一次应用程序启动时发生。 对于未经处理的异常,必须 选择加入 以发送附件。 请确保 附件文件未 命名 minidump.dmp ,因为该名称是为小型转储文件保留的。 下面是如何将文本和图像附加到报表的示例:

Crashes.GetErrorAttachments = (ErrorReport report) =>
{
    // Your code goes here.
    return new ErrorAttachmentLog[]
    {
        ErrorAttachmentLog.AttachmentWithText("Hello world!", "hello.txt"),
        ErrorAttachmentLog.AttachmentWithBinary(Encoding.UTF8.GetBytes("Fake image"), "fake_image.jpeg", "image/jpeg")
    };
};

在具有 IsCrash 属性的报表中,崩溃与未经处理的异常不同。 对于崩溃, 属性将为 true,否则为 false。

注意

当前附件的大小限制为 7 MB。 尝试发送更大的附件将触发错误。

注意

GetErrorAttachments在main线程上调用,并且不会在帧上拆分工作。 为了避免阻塞游戏循环,请勿在此回调中执行任何长时间运行的任务。

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

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

Crashes.SetEnabledAsync(false);

若要再次启用 App Center 崩溃,请使用同一 API,但作为参数传递 true

Crashes.SetEnabledAsync(true);

无需等待此调用, (其他 API 调用(例如 IsEnabledAsync) 一致)。

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

检查是否启用了 App Center 崩溃

还可以检查是否启用 App Center 崩溃:

bool isEnabled = await Crashes.IsEnabledAsync();

Unity 中处理的异常

App Center 还允许使用 Unity 中处理的异常来跟踪错误。 为此,请使用 TrackError 方法:

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

有关错误的进一步上下文,还可以向其附加属性。 将属性作为字符串字典传递。 此步骤是可选的。

try {
    // your code goes here.
} catch (Exception exception) {
    var properties = new Dictionary<string, string>
    {
        { "Category", "Music" },
        { "Wifi", "On" }
    };
    Crashes.TrackError(exception, properties);
}

还可以选择将二进制和文本附件添加到已处理的错误报告。 将附件作为对象的数组 ErrorAttachmentLog 传递,如以下示例所示。

try {
    // your code goes here.
} catch (Exception exception) {
    var attachments = new ErrorAttachmentLog[]
    {
        ErrorAttachmentLog.AttachmentWithText("Hello world!", "hello.txt"),
        ErrorAttachmentLog.AttachmentWithBinary(Encoding.UTF8.GetBytes("Fake image"), "fake_image.jpeg", "image/jpeg")
    };
    Crashes.TrackError(exception, attachments: attachments);
}

Unity 中未经处理的异常

报告未经处理的异常

默认情况下,App Center SDK 不会报告应用中引发的未处理的异常,这些异常不会导致严重崩溃。 若要启用此功能,请调用以下方法:

Crashes.ReportUnhandledExceptions(true);

调用此 API 后,App Center 会将所有未经处理的异常记录为 App Center 门户中的问题,类似于前面提到的已处理的异常。 若要禁用此功能,请调用与 参数相同的 API 传递 false

Crashes.ReportUnhandledExceptions(false);

注意

App Center SDK 检测到的某些未经处理的异常将在 App Center UI 中显示为错误。 这是因为 Unity 默认捕获未经处理的异常,这意味着应用不会退出,也不会被视为崩溃。

将附件添加到未经处理的异常报告

默认情况下,App Center SDK 不会对未经处理的异常启用附件。 若要启用此功能,请将 enableAttachmentsCallback 方法的 ReportUnhandledExceptions 布尔参数设置为 true

Crashes.ReportUnhandledExceptions(true, true);

然后,可以选择通过实现 GetErrorAttachments 回调将附件添加到未经处理的异常报告。

报告 NDK 崩溃

报告崩溃

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

生成分隔板库

接下来,必须按照 适用于 Android 的 Google Breakpad 官方自述文件中列出的说明,包括和编译 Google Breakpad。 若要在 Unity 中使用它,请将二进制文件包含在应用中。

注意

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

附加异常处理程序

包含 Google Breakpad 后,请附加 NDK 故障处理程序:

/* Attach NDK Crash Handler. */
var minidumpDir = Crashes.GetMinidumpDirectoryAsync();
setupNativeCrashesListener(minidumpDir.Result);

...

[DllImport("YourLib")]
private static extern void setupNativeCrashesListener(string path);

方法 setupNativeCrashesListener 是必须在 C/C++ 中实现的本机方法:

#include <android/log.h>
#include "google-breakpad/src/client/linux/handler/exception_handler.h"
#include "google-breakpad/src/client/linux/handler/minidump_descriptor.h"

static google_breakpad::ExceptionHandler exception_handler(google_breakpad::MinidumpDescriptor(), NULL, dumpCallback, NULL, true, -1);

/**
 * Registers breakpad as the exception handler for NDK code.
 * @param path minidump directory path returned from Crashes.GetMinidumpDirectoryAsync()
 */
extern "C" void setupNativeCrashesListener(const char *path) {
    google_breakpad::MinidumpDescriptor descriptor(path);
    exception_handler.set_minidump_descriptor(descriptor);
}

其中 dumpCallback ,用于故障排除:

/*
 * Triggered automatically after an attempt to write a minidump file to the breakpad folder.
 */
static 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。 若要进行故障排除,可以使用详细日志来检查是否在应用重启后发送了最小umps。

注意

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

警告

断板中存在一个已知 bug,这使得无法在 x86 模拟器上捕获崩溃。

符号化

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