简介:应用性能稳定是良好用户体验中非常关键的一环,为了更好保障应用性能稳定,异常捕获在保证线上产品稳定中扮演着至关重要的角色。我们团队在推出了U-APM移动应用性能监控的产品后,帮助开发者定位并解决掉很多线上的疑难杂症。随着使用人数的增多,关注度的提高,在拜访客户和开发者的留言中,很多开发者都提出希望该产品可以支持flutter框架的异常捕获。本身我并没有做过flutter开发,所以主要是通过在现有产品能力基础上做插件实现异常的上报,这篇文章就记录我学习flutter错误处理的过程和遇到的问题。

作者:友盟+技术专家 彦克

一、背景

应用性能稳定是良好用户体验中非常关键的一环,为了更好保障应用性能稳定,异常捕获在保证线上产品稳定中扮演着至关重要的角色。我们团队在推出了U-APM移动应用性能监控的产品后,帮助开发者定位并解决掉很多线上的疑难杂症。随着使用人数的增多,关注度的提高,在拜访客户和开发者的留言中,很多开发者都提出希望该产品可以支持flutter框架的异常捕获。本身我并没有做过flutter开发,所以主要是通过在现有产品能力基础上做插件实现异常的上报,这篇文章就记录我学习flutter错误处理的过程和遇到的问题。

二、Flutter异常

Flutter 异常指的是,Flutter 程序中 Dart 代码运行时意外发生的错误事件。

三、Flutter异常特点

Dart是单进程机制,所以在这个进程中出现问题时仅仅会影响当前进程,Dart 采用事件循环的机制来运行任务,当某个任务发生异常并没有被捕获时,程序并不会退出,而直接导致的结果是当前任务的后续代码就不会被执行了,也就是说一个任务中的异常是不会影响其它任务执行的,各个任务的运行状态是互相独立的。

如:我们可以通过与 Java 类似的 try-catch 机制来捕获它。但与 Java 不同的是,Dart 程序不强制要求我们必须处理异常。

四、Flutter异常分类

在Flutter开发中,根据异常来源的不同,可以将异常分为Framework异常和App异常。Flutter对这两种异常提供了不同的捕获方式,Framework异常是由Flutter框架引发的异常,通常是由于错误的应用代码造成Flutter框架底层的异常判断引起的。而对于App异常,就是应用代码的异常,通常由未处理应用层其他模块所抛出的异常引起。根据异常代码的执行时序,App 异常可以分为两类,即同步异常和异步异常。

五、捕获方式

1.App 异常的捕获方式

捕获同步异常使用try-catch 机制:

// 使用 try-catch 捕获同步异常

try {

 throw StateError('This is a Dart exception.');

}

catch(e) {

 print(e);

}

捕获异步异常使用Future 提供的 catchError 语句:

// 使用 catchError 捕获异步异常

Future.delayed(Duration(seconds: 1))

   .then((e) => throw StateError('This is a Dart exception in Future.'))

   .catchError((e)=>print(e));

看到这里估计很多人心里会问,就不能有一种方式既可以监控同步又可以监控异步异常吗?

答案是有的。

Flutter 提供了 Zone.runZoned 方法来管理代码中的所有异常。我们可以给代码执行对象指定一个Zone,在 Dart 中,Zone 表示一个代码执行的环境范围,其概念类似沙盒,不同沙盒之间是互相隔离的。如果我们想要观察沙盒中代码执行出现的异常,沙盒提供了 onError 回调函数,拦截那些在代码执行对象中的未捕获异常。废话不多说,

Show me the code

runZoned(() {

 // 同步异常

 throw StateError('This is a Dart exception.');

}, onError: (dynamic e, StackTrace stack) {

 print('Sync error caught by zone');

});

runZoned(() {

 // 异步异常

 Future.delayed(Duration(seconds: 1))

     .then((e) => throw StateError('This is a Dart exception in Future.'));

}, onError: (dynamic e, StackTrace stack) {

 print('Async error aught by zone');

});

为了能够集中捕获 Flutter 应用中的未处理异常,最终我把main函数中的 runApp 语句也放置在 Zone 中。这样在检测到代码中运行异常时,就能根据获取到的异常上下文信息,进行统一处理了:

runZoned>(() async {

 runApp(MyApp());

}, onError: (error, stackTrace) async {

//Do sth for error

});

2.Framework异常捕获方式

Flutter 框架为我们在很多关键的方法进行了异常捕获。如果我们想自己上报异常,只需要提供一个自定义的错误处理回调即可,如:

void main() {

 FlutterError.onError = (FlutterErrorDetails details) {

   reportError(details);

 };

...

}

有没有一套从天而降的代码,能够统一处理以上异常呢?

3.总结(一套代码捕获所有异常)

runZonedGuarded(() async {

   WidgetsFlutterBinding.ensureInitialized();

FlutterError.onError = (FlutterErrorDetails details) {

     myErrorsHandler.onError(details.exception,details.stack);

   };

   runApp(MyApp());

 }, (Object error, StackTrace stack) {

   myErrorsHandler.onError(error, stack);

 });

代码中出现了一句,上诉从没有出现过的代码即WidgetsFlutterBinding.ensureInitialized(),当我把这行代码注释掉的时候,框架异常是捕获不到的。

当时困扰了好久最后终于查到了原因:

上图是Flutter的架构层,WidgetFlutterBinding用于与 Flutter 引擎交互。 我们的APM产品需要调用 native 代码来初始化,并且由于插件需要使用平台 channel 来调用 native 代码,这是异步完成的,因此必须调用ensureInitialized()确保你有一个 WidgetsBinding 的实例.

来自 docs :

Returns an instance of the WidgetsBinding, creating and initializing it if necessary. If one is created, it will be a WidgetsFlutterBinding. If one was previously initialized, then it will at least implement WidgetsBinding.

注:如果你的应用在runApp 中调用了 WidgetsFlutterBinding.ensureInitialized() 方法来进行一些初始化操作,则必须在runZonedGuarded中调用WidgetsFlutterBinding.ensureInitialized()

六、异常上报

异常上报的整体方案是通过已有的插件增加接口,桥接Android APM 和 iOS APM库的自定义异常上报接口。

插件增加函数

static void postException(error, stack) {

   List args = [error,stack];

   //将异常和堆栈上报至umapm

   _channel.invokeMethod("postException",args);

 }

Android 端调用自定义异常上报:

private void postException(List args){

   String error = (String)args.get(0);

   String stack = (String)args.get(1);

   UMCrash.generateCustomLog(stack,error);

 }

iOS端调用自定义异常上报:

if ([@"postException" isEqualToString:call.method]){

       NSString* error = arguments[0];

       NSString* stack = arguments[1];

       [UMCrash reportExceptionWithName:@"Flutter" reason:error stackTrace:stack terminateProgram:NO];

}

以上就是本期干货内容的介绍,希望我们的技术内容可以更好地帮助开发者们解决问题,我们将陪伴开发者们一起进步,一起成长。

原文链接

本文为阿里云原创内容,未经允许不得转载。

技术实践第二期|Flutter异常捕获的更多相关文章

  1. Flutter异常监控 - 壹 | 从Zone说起

    开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情 如果你正需要处理Flutter异常捕获,那么恭喜你,找对地了,这里从根源上给你准备了Flutter异常捕获 ...

  2. Flutter异常监控 - 叁 | 从bugsnag源码学习如何追溯异常产生路径

    如果觉得文章对你有帮助,点赞.收藏.关注.评论,一键四连支持,你的支持就是我创作最大的动力. ️ 本文原创听蝉 公众号:码里特别有禅 欢迎关注原创技术文章第一时间推送  ️ 前言 没错,继Flutte ...

  3. Flutter异常监控 - 贰 | 框架Catcher原理分析

    前言 在给 Flutter 应用做异常监控的时候,一开始我是拒绝滴,如果不考虑 Flutter Engine 和 native 侧的监控,用我另一篇文章中不得不知道的 Flutter 异常捕获知识点 ...

  4. 网易云社区有奖问答活动第二期——技术领导力、深入分布式、PHP圣经、Linux运维、Unity……三月热点图书等你拿!

    网易云社区第二期有奖问答活动开始了!(第一期活动已结束:人工智能图书大抽奖!) 欢迎积极参与网易云社区,讨论问题,交流心得.我们本期准备了一批技术领域热点图书,送给参与社区的朋友们,将以抽奖的形式送出 ...

  5. 祝贺|合肥.NET俱乐部第二期技术沙龙活动圆满成功

    热烈祝贺合肥.NET俱乐部第二期技术沙龙圆满成功,感恩参与活动的每一位小伙伴!正是因为有你们才促成了这次聚会的成功.现对此次活动进行简单回顾并附上精彩的活动图片,每一位参与活动者名单,以及此次活动讲师 ...

  6. Redis数据库云端最佳技术实践

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯云数据库 TencentDB发表于云+社区专栏 邹鹏,腾讯高级工程师,腾讯云数据库Redis负责人,多年数据库.网络安全研发经验. ...

  7. 灵雀云Istio技术实践专题整理

    Istio技术实践专题(1) Service Mesh Istio 基本概念和架构基础 Istio被称作Kubernetes的最佳云原生拍档.从今天起,我们推出"Istio技术实践" ...

  8. Flutter异常监控 - 肆 | Rollbar源码赏析

    一. Rollbar可以帮你解决哪些问题 无特别说明,文中Rollbar统指Rollbar-flutter 1. 代码复用 Rollbar官方文档说是纯Dart实现,该特征意味着自带"代码复 ...

  9. 寻找大学目标及行动步骤——记ITAEM团队第二期宣讲会(2014.05.14)

    ·昨晚8:00-9:40.在 钟海楼03029 ,进行了ITAEM团队第二期宣讲会(第一期见第一期宣讲会总结).来參加的主要是大一学生.以信院为主.也有法学院.文学院的同学. 在宣讲会中,大家都比較积 ...

  10. 微信团队原创分享:iOS版微信的内存监控系统技术实践

    本文来自微信开发团队yangyang的技术分享. 一.前言 FOOM(Foreground Out Of Memory),是指App在前台因消耗内存过多引起系统强杀.对用户而言,表现跟crash一样. ...

随机推荐

  1. Spring之事务传播属性

    在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量. 在使用Spring时,大部分会用到他的声明式事务,简单的在配置文件中进行一些规则 ...

  2. 3DCAT云流送技术如何搅动各大行业

    在不久前结束的数字会展上,3DCAT展位的实时云流送技术技惊四座,带来不一样的视觉体验,到访的客户都无法分辨这些数字内容是在本地还是云端运行的,每一个粒子都真实可见,有现场的参观者瞪大了双眼,直呼不可 ...

  3. 利用kali自带的msfvenom工具生成远程控制软件

    一.首先还是得打开postgresql service postgresql start 然后让我们看看它有哪些功能 部分参数 -p 选择一个载荷,或者说一个模块吧. -i 载荷列表 -f 生成的文件 ...

  4. 阿里云服务器安装mysql后本地连接失败

    阿里云服务器安装mysql后本地连接失败 一.问题描述 在阿里云安装mysql后,想在本地电脑用可视化工具连接mysql,但是提示连接失败 错误如图所示: 二.问题分析 1.检查3306端口 首先,检 ...

  5. Oracle存储过程打印输出错误信息、行号,快速排查

    测试存储过程如下: create or replace procedure prc_test is p_1 varchar2(2); begin p_1 := 'lxw测试'; exception w ...

  6. 英语文档阅读学习系列之Zynq-7000 EPP Software Developers Guide

    阅读ug821-zynq-7000-swdev记录 1.略看目录Table 依旧采用总说加解释的模式,这种方式易于查找,是可靠的框架.目录词条依次为: Introduction Software Ap ...

  7. SMASH:经典One-Shot神经网络搜索,仅需单卡 | ICLR 2018

    SMASH方法使用辅助网络生成次优权重来支持网络的快速测试,从结果来看,生成的权重与正常训练的权重在准确率上存在关联性,整体搜索速度很快,仅需要单卡进行搜索,提供了一个很好的新思路.   来源:晓飞的 ...

  8. 表的唯一约束的作用 KingbaseES VS Oracle

    背景 演示唯一约束怎样创建.删除.禁用和使用唯一性约束,已经多种数据库的差异. 什么是唯一约束 唯一性约束指表中一个字段或者多个字段联合起来可以唯一标识一条记录的约束, 字段中,可以包括空值. 唯一性 ...

  9. Python爬取腾讯疫情实时数据并存储到mysql数据库

    思路: 在腾讯疫情数据网站F12解析网站结构,使用Python爬取当日疫情数据和历史疫情数据,分别存储到details和history两个mysql表. ①此方法用于爬取每日详细疫情数据 1 impo ...

  10. Tomcat内存马回显

    回顾JSP马 详情见:https://www.cnblogs.com/F12-blog/p/18111253 之前说的都是利用 jsp 注入内存马,但 Web 服务器中的 jsp 编译器还是会编译生成 ...