Flutter应用开发:捕捉Bug的正确位置
在软件开发过程中,错误和异常总是不可避免的。
无论是客户端的逻辑错误,还是服务端的数据问题,只要出现异常,我们就需要一种机制来通知我们以便处理。
在应用开发过程中,我们可能会通过一些第三方平台如Fabric、Bugly等开启异常日志上报。
Flutter也有一些第三方平台,比如Sentry,可以实现异常日志上报。
但更笼统地说,本文并没有具体解释第三方平台上的异常日志捕获。我们将告诉你如何在 Flutter 中保存异常。
至于具体的上报方式,无论是向自己的后台上报,还是通过第三方SDK API上报异常,都是可以的。
演示开始状态
首先我们新建一个Flutter项目,编辑main.dart代码如下:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Flutter Crash Capture'),),
body: MyHomePage(),
),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container();
}
}
复制代码
效果如下:
捕获错误
编辑MyHome列表页面。并进行越界访问,更改一些代码如下:
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
List<String> numList = ['1', '2'];
print(numList[6]);
return Container();
}
}
复制代码
可以看到控制台错误如下:
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following RangeError was thrown building MyHomePage(dirty):
flutter: RangeError (index): Invalid value: Not in range 0..1, inclusive: 6
复制代码
当然,这些错误信息也出现在用户界面(调试模式)中。
那么我们如何捕捉它呢?
其实很简单。有一个一般模式。模型为:
import 'dart:async';
import 'package:flutter/material.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 {
// TODO
}
复制代码
在TODO 中,您可以执行埋点的报告功能或其他处理。
完整的例子如下:
import 'dart:async';
import 'package:flutter/material.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);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Flutter Crash Capture'),),
body: MyHomePage(),
),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
List<String> numList = ['1', '2'];
print(numList[6]);
return Container();
}
}
复制代码
运行时会看到控制台检测到的错误是:
flutter: catch error=RangeError (index): Invalid value: Not in range 0..1, inclusive: 6
复制代码
assert Magical Use
我们知道通常只有打包后才需要报错并释放。
如果您在正常调试过程中遇到错误,我们会定位问题并修复。
所以在调试模式下我们不想报告错误,我们想将它们直接打印到控制台。
所以现在我们需要一种方法来区分调试模式和发布模式。如何区分?
此时必须使用验证。
bool get isInDebugMode {
// Assume you're in production mode.
bool inDebugMode = false;
// Assert expressions are only evaluated during development. They are ignored
// in production. Therefore, this code only sets `inDebugMode` to true
// in a development environment.
assert(inDebugMode = true);
return inDebugMode;
}
复制代码
从注释中还可以看出,断言子句仅在开发环境中有效,在生产环境中被忽略。
所以利用这个我们就可以实现我们的需求了。
上面的结论很容易验证,我们就不介绍了。
完整模型
import 'dart:async';
import 'package:flutter/material.dart';
Future<Null> main() async {
FlutterError.onError = (FlutterErrorDetails details) async {
if (isInDebugMode) {
FlutterError.dumpErrorToConsole(details);
} else {
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 {
// TODO
}
bool get isInDebugMode {
// Assume you're in production mode.
bool inDebugMode = false;
// Assert expressions are only evaluated during development. They are ignored
// in production. Therefore, this code only sets `inDebugMode` to true
// in a development environment.
assert(inDebugMode = true);
return inDebugMode;
}
复制代码
调试模式下,错误会直接打印到控制台,帮助定位问题。
发布模式下,错误信息会被收集并上传到服务器。
作者:Android小宇
来源:掘金
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。