[译] 使用 Catcher 处理 Flutter 错误

2,936 阅读9分钟
说明:这是一篇介绍 Flutter 错误处理的文章,翻译自国外的一篇博客,若有翻译不准确或文字表达上的不足之处,欢迎指正。原文链接:medium.com/flutter-com…
作者:
Jakub Homlala


本图片源自UnsplashChor Hung Tsang

错误处理是程序员每天的工作,这事儿在日常工作中是没完没了的。在 Dart 语言中,我们可以用 try-catch 语言结构轻松地处理错误。但是,如果我们忘了写 try-catch 代码会怎样?我们会得到一个像下面这样的“红屏错误页面”。


是的,我们的代码不都总是运行良好。每一个开发者都会有疏忽。但好的开发者会解决他所犯的失误。

对用户来说,一个重要的事情是,当我们是一个 APP 的用户的时候,我们需要知道一些超出预期的事发生了,并且我们可以决定是否发送错误日志给开发者。错误日志会帮助开发者修复错误。

开发者能修复错误,但他们需要知道发生了什么错误和在哪儿发生的错误。在移动应用开发中,我们需要一个可以报告程序异常行为给开发者的工具。目前,在 Flutter 中我们已经支持了 Sentry 错误追踪功能,很快也会支持 Firebase 的 Crashlytics。但是,如果我们不想使用 Sentry 或 Crashlytics 怎么办呢?如果我们使用一些配置简单,还可以在开发阶段甚至在已发布后捕获错误的通用的工具,那该怎么实现呢?这个工具包含发送邮件的功能,用户只需点击“发送” 就可以把错误反馈给开发者,或者把崩溃日志保存到设备的存储器中。这就是接下来将要介绍的 Catcher 了。

Catcher 简介


Catcher 的 logo

Catcher 是一个新的捕获和处理错误信息的 Flutter 插件。Catcher 提供多种错误报告模型和处理程序,以配合 Flutter 应用程序。Catcher 深受 ACRA 的启发。

Catcher 报告流程是很容易理解的(参看下图)。Catcher 将错误处理程序注入到你的应用程序中,从而可以捕获所有未经检测的错误。一旦它捕获到错误,他就创建报告并将其发送到reporter 中。reporter 显示错误的相关信息并等待用户决策。如果用户接受报告错误,则处理程序(handlers)将处理该报告。

你也可以报告你在 try catch 中检查到的错误。

Catcher 也会收集用户设备硬件和操作系统的信息。这些数据的获取是可以不经用户任何形式的授权,因为它不含有用户的个人信息。这些数据是很有帮助的,因为有些时候产生错误是因为设备的问题而不是开发者的问题。


Catcher 原理图

如何使用 Catcher

让我们看一个使用 Catcher 的基本例子。首先我们需要安装插件。到你的 pubspec.yaml 文件中加上下面内容:

dependencies:
  catcher: ^0.0.8

然后,你需要执行 packages get 命令下载和安装到你的项目中。

最后一步是加上这一句 import:

import ‘package:catcher/catcher_plugin.dart';

我们已经准备好使用 Catcher了,下面就是使用 Catcher 的基本例子。

main() {
  //debug configuration  CatcherOptions debugOptions =
      CatcherOptions(DialogReportMode(), [ConsoleHandler()]);

  //release configuration
  CatcherOptions releaseOptions = CatcherOptions(DialogReportMode(), [
    EmailManualHandler(["recipient@email.com"])  ]);

  //profile configuration
  CatcherOptions profileOptions = CatcherOptions(
    NotificationReportMode(),
    [ConsoleHandler(), ToastHandler()],
    handlerTimeout: 10000,
    customParameters: {"example": "example_parameter"},
  );
  //MyApp is root widget
  Catcher(MyApp(),
      debugConfig: debugOptions,
      releaseConfig: releaseOptions,
      profileConfig: profileOptions);
}

通常情况下,当你执行你的代码,你的 main 函数只有这一行:runApp(MyApp()); ,这一行代码用来启动应用。当你使用 Catcher 的时候,你将不再使用这一行代码。替代上面的方式,你需要用根 Widget 和 应用配置创建 Catcher 实例。

Catcher 允许你同时设置 3 种配置: debug , releaseprofile 。在上面的代码中,我们创建了 3 个 CatcherOptions 实例,分别描述 Catcher 在不同模式下的行为方式。当应用运行在 debug 环境时,Catcher 会使用 debugConfig ,当应用运行在发布环境时会使用 releaseConfig 当运行在 “profile” 模式时,会使用 profileConfig

在每一个 CatcherOptions 实例中,你可以配置不同的 报告模型和处理程序列表。点击这里可以查看 CatcherOptions 的所有的配置参数。

有 4 种报告模式:

  • 静默报告模式
  • 通知报告模式
  • 对话框报告模式
  • 页面报告模式

有 6 种处理程序类型:

  • Console 处理程序
  • Http 处理程序
  • 文件处理程序
  • Toast 处理程序
  • 自动邮件处理程序
  • 手动邮件处理程序


当你创建 Catcher 实例的时候,它将会启动你的根 Widget 并侦听应用程序中发生的任何错误。在调试模式下运行上面的代码,一旦有错误发生,将会显示一个对话框,用户可以在对话框中做出是否报告错误的决策。一旦用户接受报告错误,错误将由 Console 处理程序处理错误并将错误信息简单地打印到 Console 中。

你可以在这里找到基础示例的完整代码。



使用对话框报告模式和 Console 处理程序的基础示例,Console 中显示了完整的报告数据

报告模式

让我们谈一谈报告的模式。如你所知,报告模式是我们向用户显示错误信息的方式。下面,让我们更详细的了解一下每种报告模式。

静默报告模式是一种不需要用户做任何操作的模式。不会有任何错误相关的信息显示给用户。用户也不会知道任何关于错误的情况,除非有一些可视化的处理程序显示了错误信息(例如,Toast 处理程序)。当你不想询问用户以获取处理错误的权限时,你可以使用此报告模式。

示例代码:

CatcherOptions(SilentReportMode(), [ConsoleHandler()]);

通知报告模式显示用户本地通知。一旦用户点击了它,报告将被配置的处理程序接受并处理。

示例代码:

CatcherOptions(NotificationReportMode(), [ConsoleHandler()]);

对话框报告模式会向用户显示一个对话框。对话框中有两个按钮:“同意”和“取消”。点击“同意”按钮将推送错误日志到处理程序,点击“取消”将解除报告。

CatcherOptions(
    DialogReportMode(
        titleText: "Title",
        descriptionText: "Description",
        acceptText: "Accept",
        cancelText: "Cancel"),
    [ConsoleHandler()]);


页面报告模式显示一个新的全屏页面,其中包括错误描述信息、栈跟踪、和两个按钮。

CatcherOptions(
    PageReportMode(
        titleText: "Title",
        descriptionText: "Description",
        acceptText: "Accept",
        cancelText: "Cancel",
        showStackTrace: false),
    [ConsoleHandler()]);

对话框报告模式和页面报告模式需要在应用中配置 navigation key 。这是非常简单的,你只需要在你的 MaterialApp widget 中增加一行代码。

@override  Widget build(BuildContext context) {
    return MaterialApp(
      //********************************************
      navigatorKey: Catcher.navigatorKey,
      //********************************************
      home: Scaffold(
          appBar: AppBar(
            title: const Text('Plugin example app'),
          ),
          body: ChildWidget()),
    );
  }

报告模式有多个配置选项。你可以在这里找到所有的配置项。



报告模式(从上到下依次为):通知模式,对话框模式,页面模式。静默模式没有任何可视界面

处理程序

在报告流程中,处理程序是最后一个环节。它们消费报告并对报告做一些处理。在每一个配置组中,你可以设置多个处理程序,例如 Console 处理程序、文件处理程序。让我们更进一步地了解每一种 处理程序。

Console 处理程序 是一个基本的处理程序。它会打印格式化的报告到控制台中。你可以配置 Console 处理程序打印或不打印报告的某些部分。

示例代码:

CatcherOptions(DialogReportMode(), [
  ConsoleHandler(
      enableApplicationParameters: true,
      enableCustomParameters: true,
      enableStackTrace: true,
      enableDeviceParameters: true)
]);


控制台处理程序


文件处理程序把错误日志保存到用户的设备中。你只需传入保存文件的路径。

示例代码:

Directory externalDir = await getExternalStorageDirectory();

String path = externalDir.path.toString() + "/log.txt";

CatcherOptions debugOptions = CatcherOptions(DialogReportMode(),
 [FileHandler(File(path))]);

CatcherOptions releaseOptions = CatcherOptions(DialogReportMode(),
 [FileHandler(File(path))]);

Catcher(MyApp(), debugConfig: debugOptions, releaseConfig:
 releaseOptions);


文件处理程序保存报告到文件中

Http 处理程序允许用户通过 Http 请求发送数据到服务器。目前,只支持 Http POST 方式的请求。你可以在请求中添加自定义的 header。

示例代码:

CatcherOptions(DialogReportMode(), [
  HttpHandler(HttpRequestType.post,
 Uri.parse("http://logs.server.com"),
      headers: {"header": "value"},
 requestTimeout: 4000, printLogs: false)
]);

有一个用 Java 实现的简单的 Catcher 报告服务端。你可以在这里找到。


后端服务器显示了收集到的报告。

自动邮件处理程序增加了发邮件功能。此处理程序自动发送邮件到指定的邮箱。你需要设置好用于发送邮件的用户名和密码,因此,我推荐仅在开发阶段使用此处理方式。

示例代码:

CatcherOptions(DialogReportMode(),
    [EmailAutoHandler(
        "smtp.gmail.com", 587,
        "somefakeemail@gmail.com",
        "Catcher", 
       "FakePassword", ["myemail@gmail.com"])
    ]);


从自动邮件处理程序收到的邮件。

手动邮件处理程序与自动邮件处理程序不同。此处理程序创建邮件并打开默认的邮件应用。用户需要完成发送邮件的操作。你无需指定发件人的用户名和密码,因为用户会将使用他自己的邮箱作为发件人,所以,在发布阶段使用此方式是安全的。

示例代码:

CatcherOptions(DialogReportMode(), [
  EmailManualHandler(["email1@email.com", "email2@email.com"],
      enableDeviceParameters: true,
      enableStackTrace: true,
      enableCustomParameters: true,
      enableApplicationParameters: true,
      sendHtml: true,
      emailTitle: "Sample Title",
      emailHeader: "Sample Header",
      printLogs: true)
]);


邮件处理程序生成的示例邮件

Toast 处理程序是最后一种处理程序。它在用户屏幕上显示 toast 。当你只需要给用户显示简短的信息时,这非常有用。

示例:

CatcherOptions(DialogReportMode(), [
  ToastHandler(
      gravity: ToastHandlerGravity.bottom,
      length: ToastHandlerLength.long,
      backgroundColor: Colors.red,
      textColor: Colors.white,
      textSize: 12.0,
      customMessage: "We are sorry but unexpected error occured.")
]);


Toast 处理程序显示带有错误信息的 Toast

所有处理程序和它们的配置选项的介绍可以在这里找到。

你甚至可以定义你自己的处理程序!只需要创建一个继承自 ReportHandler 的类:

import 'package:catcher/catcher_plugin.dart';

class MyHandler extends ReportHandler{
  @override  Future<bool> handle(Report error) async{
    //my implementation
    return true;
  }  
}

小结

Catcher 是一个新的插件,但是很强大。此插件还在开发中,但你可以在你的项目中使用了。在你的项目中实现它非常的简单直接,值得一试!

你可以在 GitHub 中自由地报告问题或提供反馈,也欢迎你向 Catcher 增加新的功能。欢迎自由地为这个项目做贡献!

项目 GitHub 地址:github.com/jhomlala/ca…

谢谢阅读!