Flutter崩溃时将rout堆栈上报到服务端

 

一、

捕获崩溃并上传

void main() async {

FlutterError.onError = (error) {

Zone.current.handleUncaughtError(error.exception, error.stack);

};

 

runZonedGuarded<Future<Null>>(

() async {

await _init();

},

(error, stack) async {

String errorStack = '【${error.toString()}】 \n $stack';

errorStack = '$errorStack \n 最后访问的最多$maxNavCount个页面路径如下:\n';

String extra = await navList2String();

errorStack = '$errorStack $extra';

 

//自己实现

CrashUploadChannel crashUploadChannel = CrashUploadChannel();

crashUploadChannel.uploadCrash(errorStack);

},

);

}

 

 

二、

在MaterialApp中监控navigator

 

Widget _buildMainApp(BuildContext context) {

return MaterialApp(

navigatorObservers: [

UserNavigatorObserver(),

],

 

 

三、

user_navigator_observer.dart实现

 

 

import 'dart:collection';

 

import 'package:flutter/cupertino.dart';

import 'package:flutter/widgets.dart';

 

const Duration delayDuration = Duration(seconds: 2);

 

final maxNavCount = 20;

final _navList = ListQueue<NavEntry>();

 

void addNavEntry(NavEntry entry) {

if (_navList.length > maxNavCount) {

_navList.removeFirst();

}

 

_navList.add(entry);

}

 

Future<String> navList2String() async {

String result = '';

try {

// didPush那delay了[delayDuration],等最后一个push后再输出日志

await Future.delayed(delayDuration);

final list = _navList.toList();

list.sort((a, b) => a.time.compareTo(b.time));

result = list.join('\n');

} catch (e) {}

return result;

}

 

class NavEntry {

final String pageName;

final String action;

final DateTime time;

String extra;

 

NavEntry({

@required this.pageName,

@required this.action,

@required this.time,

});

 

@override

String toString() {

return 'Action: $action PageName: $pageName Time: $time Extra: $extra';

}

}

 

class UserNavigatorObserver extends NavigatorObserver {

@override

void didPush(Route route, Route previousRoute) {

try {

addNavEntry(NavEntry(

pageName: route.toString(),

action: 'didPush',

time: DateTime.now(),

));

} catch (e) {

print('$e');

}

}

 

@override

void didPop(Route route, Route previousRoute) {

try {

addNavEntry(NavEntry(

pageName: route.toString(),

action: 'didPop',

time: DateTime.now(),

));

} catch (e) {

print('$e');

}

}

}