Flutter 项目中集成腾讯 Bugly(flutter_bugly)异常上报

本文基于本工程已有的接入方式,介绍如何在 Flutter 端通过 flutter_bugly 完成异常与崩溃相关的上报,并把“同步异常、异步异常、平台未捕获异常”统一纳入 Bugly。

工程里做了什么

  1. pubspec.yaml 中引入依赖 flutter_bugly: ^1.1.1
  2. lib/main.dart 中:
    • 仅 Android 平台初始化 Bugly
    • 使用 runZonedGuarded + FlutterError.onError + PlatformDispatcher.instance.onError 三层兜底捕获异常
    • 把异常上传到 Bugly

1) 添加依赖(pubspec.yaml)

在本工程 pubspec.yaml 已有如下依赖:

# 腾讯 Bugly(Flutter 异常 + 原生崩溃,仅 Android 时在 main 中按平台初始化)
flutter_bugly: ^1.1.1

这一步的核心意义是:后续在 main.dart 里可以直接调用 FlutterBugly.init / uploadException / setUserId 等能力。

2) 在 main.dart 初始化 Bugly(仅 Android)

工程在 main()runZonedGuarded 里完成初始化,关键点如下:

  1. 先确保 Flutter binding:
WidgetsFlutterBinding.ensureInitialized();
  1. 仅在非 Web 且 Android 平台初始化(iOS 不在这里初始化):
if (!kIsWeb && Platform.isAndroid) {
  await FlutterBugly.init(
    androidAppId: 'YOUR_APP_ID',
    channel: 'default',
    debugMode: debugmode,
  );
  await FlutterBugly.setUserId(await const AndroidId().getId() ?? '');
}

说明:

  • androidAppId:Bugly 控制台申请的 AppId。
  • channel:发布渠道(这里固定为 default)。
  • debugMode: debugmode:Debug 下也会开上传模式(适合联调,但上线后是否要关闭取决于你们的噪音策略)。
  • userId 使用 android_id 获取设备标识,便于 Bugly 回溯到具体终端。

工程中注释明确提到:flutter_bugly 与原生 Application init 已移除相配合,因此初始化放在 Flutter 的 main 入口集中管理更直观。

3) 统一捕获并上报异常链路(FlutterError + Zone + PlatformDispatcher)

这部分是接入 Bugly 的“主价值”:让异常不只打印在控制台,而是被结构化采集、同时上传 Bugly。

3.1 同步 Flutter 异常:FlutterError.onError

工程通过重写 FlutterError.onError 来接住同步异常,并同时做:

  • 组装 logData(包含异常类型、系统信息、BaseConstants.keyVersion 版本号、locale 等)
  • 调用 FlutterBugly.uploadException 上传到 Bugly

上传时使用了:

FlutterBugly.uploadException(
  message: details.exceptionAsString(),
  detail: details.stack?.toString() ?? StackTrace.current.toString(),
  type: details.exception.runtimeType.toString(),
);

3.2 异步未捕获异常:runZonedGuarded 的 error 回调

runZonedGuarded 除了包裹初始化与 runApp,还提供了异步异常兜底:

  • 在 error 回调里同样组装结构化日志
  • 同样在 Android 调用 FlutterBugly.uploadException

这样能覆盖很多“Future/Stream 回调里抛出的异常”场景。

3.3 平台层未捕获异常:PlatformDispatcher.instance.onError

工程还补了一层“兜底”:

PlatformDispatcher.instance.onError = (error, stack) {
  if (!kIsWeb && Platform.isAndroid) {
    FlutterBugly.uploadException(
      message: "PlatformDispatcher:$error",
      detail: stack.toString() ?? StackTrace.current.toString(),
      type: error.runtimeType.toString(),
    );
  }
  return true;
};

该返回 true 的含义是:通知 Flutter 这类 onError 已处理,避免重复报错。

4) 用户标识与回溯策略(setUserId)

工程在初始化时通过:

await FlutterBugly.setUserId(await const AndroidId().getId() ?? '');

把每次上报绑定到 AndroidId。这对定位“某一批设备/某个用户群”的异常非常关键。

建议你们在后续演进时统一策略:

  • 如果上线后希望按账号维度追踪,把 setUserId 改成“登录账号 userId”
  • 如果还未有账号体系,则保留设备维度即可

5) 如何验证是否真的上报成功

你可以按下面顺序验证(建议只在 Android 上做):

  1. Debug 环境启动 App,触发一个可控异常(例如在某个按钮点击处直接抛出异常)
  2. 确认 Bugly 控制台是否能收到对应上传事件
  3. 再测一个异步异常(比如 Future.delayed(...).then((_) => throw ...)),看 Zone 兜底是否也能上传