咱們知道,在軟件開發過程當中,錯誤和異常老是在所不免。express
無論是客戶端的邏輯錯誤致使的,仍是服務器的數據問題致使的,只要出現了異常,咱們都須要一個機制來通知咱們去處理。服務器
在 APP 的開發過程當中,咱們經過一些第三方的平臺,好比 Fabric、Bugly 等能夠實現異常的日誌上報。app
Flutter 也有一些第三方的平臺,好比 Sentry 能夠實現異常的日誌上報。less
可是爲了更加通用一些,本篇不具體講解配合某個第三方平臺的異常日誌捕獲,咱們會告知你們如何在 Flutter 裏面捕獲異常。async
至於具體的上報途徑,無論是上報到自家的後臺服務器,仍是經過第三方的 SDK API 接口進行異常上報,都是能夠的。ide
首先咱們新建 Flutter 項目,修改 main.dart 代碼以下:ui
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(); } }
效果以下:this
咱們修改 MyHomePage,添加一個 List 而後進行越界訪問,改動部分代碼以下:lua
class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { List<String> numList = ['1', '2']; print(numList[6]); return Container(); } }
能夠看到控制檯報錯以下:debug
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
固然這些錯誤信息在界面上也有顯示(debug 模式)。
那麼咱們如何捕獲呢?
其實很簡單,有個通用模板,模板爲:
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
咱們知道,通常錯誤上報都是在打包發佈到市場後才須要。
平時調試的時候若是遇到錯誤,咱們是會定位問題並修復的。
所以在 debug 模式下,咱們不但願上報錯誤,而是但願直接打印到控制檯。
那麼,這個時候就須要一種方式來區分如今是 debug 模式仍是 release 模式,怎麼區分呢?
這個時候就須要用到 assert 了。
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; }
從註釋也能夠知道,assert 表達式只在開發環境下會起做用,在生產環境下會被忽略。
所以利用這一個,咱們就能夠實現咱們的需求。
上面的結論要驗證也很簡單,咱們就不演示了。
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; }
debug 模式下,直接將錯誤打印到控制檯,方便定位問題。
release 模式下,將錯誤信息收集起來,上傳到服務器。
參考連接:
Report errors to a service