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