简介:利用性能稳固是良好用户体验中十分要害的一环,为了更好保障利用性能稳固,异样捕捉在保障线上产品稳固中扮演着至关重要的角色。咱们团队在推出了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]; }
以上就是本期干货内容的介绍,心愿咱们的技术内容能够更好地帮忙开发者们解决问题,咱们将陪伴开发者们一起提高,一起成长。
原文链接
本文为阿里云原创内容,未经容许不得转载。