Flutter crash log collection - flutter崩溃日志收集

Flutter异常分类

可以分为三大类

  1. Dart异常
  2. Framework异常
  3. Engine异常

1. Dart异常捕获

局部捕获

//使用try-catch捕获同步异常
try {
  throw StateError('This is a Dart exception');
}catch(e) {
  print(e);
}

//使用catchError捕获异步异常
Future.delayed(Duration(seconds: 1))
    .then((e) => throw StateError('This is a Dart exception in Future.'))
    .catchError((e)=>print(e));

全局捕获:在dart代码中,zone表示一段代码执行的范围,概念类似iOS的沙盒,不同沙盒之间是相互隔离的。如果想要处理zone中代码执行的异常,可以通过其提供的onError回调来处理,如下:

//同步抛出异常
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');
});

2. Framework异常捕获

Framework异常是指flutter框架引起的异常,通常是由于执行错误的应用代码造成Flutter框架底层异常判断引起的,当出现Framework异常时,系统会自动弹出一个的红色错误界面。之所以会弹出一个错误提示页面,是由于系统在调用build()方法构建页面时会进行try-catch处理,如果出现任何错误就会调用ErrorWidget页面展示异常信息,并且Flutter框架在很多关键位置都自动进行了异常捕获处理。
可以通过重写ErrorWidget.builder()方法给用户更友好的界面呈现,代码如下:

ErrorWidget.builder = (FlutterErrorDetails flutterErrorDetails){
 //自定义错误提示页面
 return Scaffold(
   body: Center(
     child: Text("Custom Error Widget"),
   )
 );
};

同时可以注册 FlutterError.onError 回调,用于收集 Flutter framework 外抛的异常。

综上所述,对于dart和framework两种异常,可以在main.dart统一处理,如下:

Future<Null> main() async {
  FlutterError.onError = (FlutterErrorDetails details) async {
    Zone.current.handleUncaughtError(details.exception, details.stack);
  };

  runZoned<Future<void>>(() async {
    runApp(MyApp());
  },  onError: (error, stackTrace) async {
    await _reportError(error, stackTrace);
  });
}

Future<Null> _reportError(dynamic error, dynamic stackTrace) async {
  print('catch error='+error);
}

同时,对于开发环境和线上环境还需要区别对待。因为,对于开发环境遇到的错误,一般是可以立即定位并修复问题的,而对于线上问题才需要对日志进行上报。因此,对于错误日志上报,需要对开发环境和线上环境进行区分对待,如下所示:

Future<Null> main() async {
  FlutterError.onError = (FlutterErrorDetails details) async {
    if (isDebugMode) {
      FlutterError.dumpErrorToConsole(details);
    } else {
      Zone.current.handleUncaughtError(details.exception, details.stack);
    }
  };//省略其他代码
}

bool get isDebugMode {
  bool inDebugMode = false;
  assert(inDebugMode = true);
  return inDebugMode;
}

3. Flutter engine 异常捕获

flutter engine 部分的异常,以Android 为例,主要为 libfutter.so发生的错误。

这部份可以直接交给native崩溃收集sdk来处理,比如 firebase crashlytics、 bugly、xCrash 等等