You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MAUI应用中全局捕获异常并向用户展示?

MAUI 全局异常捕获与用户提示正确方案

问题根源分析

你之前用FirstChanceException事件+DisplayAlert导致崩溃的核心原因是:这个事件会捕获所有异常(包括系统内部已被try/catch处理的小异常,比如绑定失败、控件加载警告等),频繁触发弹窗会阻塞UI线程、引发多弹窗冲突,最终导致应用崩溃。而且用户不需要知道这些被系统处理的异常,只需要知晓真正会导致应用不稳定的未处理异常。

正确实现步骤

1. 选择合适的异常捕获事件

优先使用以下两个事件捕获未处理异常(覆盖同步/异步场景),而非FirstChanceException:

  • AppDomain.CurrentDomain.UnhandledException:捕获同步代码中的未处理异常
  • TaskScheduler.UnobservedTaskException:捕获异步代码中未被观察到的异常

2. 在App类中注册事件,通过UI线程安全弹窗

App类中可以通过MainThread确保弹窗在UI线程执行,同时避免直接阻塞事件处理逻辑:

public App()
{
    InitializeComponent();

    // 注册全局异常事件
    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;

    MainPage = new AppShell();
}

private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
    var exception = e.ExceptionObject as Exception;
    if (exception == null) return;

    // 用MetroLog记录异常日志
    LogManagerFactory.DefaultLogManager.GetLogger<App>().Fatal("未处理同步异常", exception);
    
    // 切换到UI线程显示弹窗
    MainThread.BeginInvokeOnMainThread(async () => await ShowErrorAlert(exception));
}

private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
    // 标记异常已处理,避免应用强制崩溃
    e.SetObserved();
    var exception = e.Exception.InnerException ?? e.Exception;

    LogManagerFactory.DefaultLogManager.GetLogger<App>().Fatal("未处理异步异常", exception);
    
    MainThread.BeginInvokeOnMainThread(async () => await ShowErrorAlert(exception));
}

private async Task ShowErrorAlert(Exception ex)
{
    var mainPage = Application.Current?.MainPage;
    if (mainPage == null) return;

    // 防止重复弹出弹窗
    if (mainPage.IsBusy) return;
    
    mainPage.IsBusy = true;
    await mainPage.DisplayAlert(
        "应用错误", 
        $"抱歉,应用发生了未预料的问题:\n{ex.Message}", 
        "我知道了"
    );
    mainPage.IsBusy = false;
}

3. 可选:按需记录所有异常(仅日志,不弹窗)

如果需要记录所有异常(包括已被处理的),可以保留FirstChanceException事件,但只用来写日志,绝对不要在这个事件里显示弹窗:

AppDomain.CurrentDomain.FirstChanceException += (s, e) =>
{
    LogManagerFactory.DefaultLogManager.GetLogger<App>().Debug("异常触发", e.Exception);
};

额外注意事项

  • 平台特定异常:针对Android/iOS的原生异常,可以在各自的平台项目中添加补充处理(比如Android的UncaughtExceptionHandler),但上述跨平台事件已覆盖绝大多数场景。
  • 弹窗内容优化:给用户看的提示尽量简洁,不要暴露技术细节(比如堆栈信息),可以只显示友好提示,详细日志留给开发者排查。

内容的提问来源于stack exchange,提问作者Val

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 14:55:02