Flutter全局捕获报错信息

本文最后更新于:3 个月前

一、系统方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import 'dart:async';
import 'package:demo_error/Page1.dart';
import 'package:flutter/material.dart';

GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

void main() {
_reportError(dynamic error, dynamic stackTrace) async {
showDeleteConfirmDialog1(error.toString() + stackTrace.toString());
}

// 捕获同步代码的报错
FlutterError.onError = (FlutterErrorDetails details) async {
await _reportError(details.exception, details.stack);
};
runZoned(() async {
runApp(MyApp());
}, onError: (error, stackTrace) async {
// 捕获异步代码的报错
await _reportError(error, stackTrace);
});
}

// 弹出对话框
Future<bool> showDeleteConfirmDialog1(String content) {
return showDialog<bool>(
context: navigatorKey.currentState.overlay.context,
builder: (context) {
return AlertDialog(
title: Text("提示"),
content: Text(content),
actions: <Widget>[
FlatButton(
child: Text("确定"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
title: 'Error',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: '主页'),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;

@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
child: Text('同步数组越界'),
onPressed: () {
List<int> a = [1, 2];
int i = a[2];
print(i);
},
),
RaisedButton(
child: Text('异步数组越界'),
onPressed: () {
Future.delayed(Duration(seconds: 2)).then((value) {
List<int> a = [1, 2];
int i = a[2];
print(i);
});
},
),
],
),
),
);
}
}

  1. main()中两个方法分别对应同步的报错和异步的报错
  2. 为了将报错信息使用弹窗弹出,所以用GlobalKey来获取全局的context
  3. 如果直接运行flutter工程,从main()启动,是无法看到效果的,必须使用Xcode或者Android Studio运行iosandroid目录下的原生工程才能看到效果,具体原因暂不清楚

二、第三方插件catcher

https://pub.dev/packages/catcher

同样需要运行原生工程才有效果,此插件底层用的仍是上面的官方方法,在外层进行了封装,封装了其他非弹窗形式的提醒效果