开发者总是试图创造没有 bug 的应用,但是 bug 还是会时不时地出现。这些 bug 会给用户带来糟糕的体验,所以获知 bug 发生的位置以及出现的频率就显得极为关键了。这样,你就可以根据 bug 的影响程度优先修复它们。

如何确定用户遇到 bug 的频率呢?解决方案是:当异常发生时,生成一份日志,日志中包含发生的异常及相关的堆栈信息。随后,可以将日志发送到异常监控报警平台,比如 Sentry、Fabric 或者 Rollbar。

异常监控报警平台会将上报的崩溃日志异常信息聚合并分组归类,这样就可以知道应用程序出现异常的频率并定位异常发生位置。

这个章节中,将会介绍如何把异常信息上报给异常监控报警平台 Sentry

步骤

  • 从 Sentry 平台获取 DSN

  • 导入 Sentry 包

  • 创建 SentryClient

  • 创建上报异常的函数

  • 捕获并上报 Dart 异常

  • 捕获并上报 Flutter 异常

1. 从 Sentry 平台获取 DSN

在向 Sentry 上报异常信息前,需要在 Sentry.io 上获取应用的唯一身份标识 DSN。

根据以下步骤,获取 DSN:

2. 导入 Sentry 包

导入 sentry 包到应用中,sentry 包会让异常上报更为方便。

  1. dependencies:
  2. sentry: <latest_version>

3. 创建 SentryClient

创建 SentryClient 用于将异常日志上报给 sentry 平台。

  1. final SentryClient _sentry = SentryClient(dsn: "App DSN goes Here");

4. 创建上报异常的函数

Sentry 的相关内容都设置好后,就可以开始上报异常了。通常在开发环境下可能不需要把异常上报到 Sentry,所以可以先创建一个函数来区分当前环境是开发环境还是生产环境。

  1. bool get isInDebugMode {
  2. // Assume you're in production mode
  3. bool inDebugMode = false;
  4. // Assert expressions are only evaluated during development. They are ignored
  5. // in production. Therefore, this code only sets `inDebugMode` to true
  6. // in a development environment.
  7. assert(inDebugMode = true);
  8. return inDebugMode;
  9. }

然后,用这个函数结合 SentryClient 就可以实现生产环境的异常上报了。

  1. Future<void> _reportError(dynamic error, dynamic stackTrace) async {
  2. // Print the exception to the console
  3. print('Caught error: $error');
  4. if (isInDebugMode) {
  5. // Print the full stacktrace in debug mode
  6. print(stackTrace);
  7. return;
  8. } else {
  9. // Send the Exception and Stacktrace to Sentry in Production mode
  10. _sentry.captureException(
  11. exception: error,
  12. stackTrace: stackTrace,
  13. );
  14. }
  15. }

5. 捕获并上报 Dart 异常

现在已经有了一个能够根据环境上报异常的函数了,接着还需要知道如何去捕获 Dart 异常。

为了实现这一目的,可以把应用运行在一个自定义的 Zone 里面。Zones 为代码建立执行上下文环境。在这个上下文环境中,所有发生的异常在抛出 onError 时都能够很容易地被捕获到。

在下面的例子中,将会把应用运行在一个新的 Zone 里面,通过 onError 回调捕获所有的异常。

  1. runZoned<Future<void>>(() async {
  2. runApp(CrashyApp());
  3. }, onError: (error, stackTrace) {
  4. // Whenever an error occurs, call the `_reportError` function. This sends
  5. // Dart errors to the dev console or Sentry depending on the environment.
  6. _reportError(error, stackTrace);
  7. });

6. 捕获并上报 Flutter 异常

除了 Dart 异常,Flutter 也能抛出其他的异常,比如调用原生代码发生的平台异常。这种类型的异常也同样是需要上报的。

为了捕获 Flutter 异常,需要重写 FlutterError.onError 属性。在开发环境下,可以将异常格式化输出到控制台。在生产环境下,可以把异常传递给上个步骤中的 onError 回调。

  1. // This captures errors reported by the Flutter framework.
  2. FlutterError.onError = (FlutterErrorDetails details) {
  3. if (isInDebugMode) {
  4. // In development mode, simply print to console.
  5. FlutterError.dumpErrorToConsole(details);
  6. } else {
  7. // In production mode, report to the application zone to report to
  8. // Sentry.
  9. Zone.current.handleUncaughtError(details.exception, details.stack);
  10. }
  11. };

完整示例

查看 Crashy 示例应用,体验完整流程。