????????1. 頁面異常監測
? ? ? ? ?在Flutter中,通常用FlutterError監測Flutter框架拋出的異常,用runZonedGuarded監測應用中用戶代碼異常。
? ? ? ? ? ??
class AppGuarded {run(Widget app) {//1. 用FlutterError監測flutter框架拋出的異常FlutterError.onError = (FlutterErrorDetails details) async {//線上環境,將異常交給zone統一處理if (kReleaseMode) {Zone.current.handleUncaughtError(details.exception, details.stack!);} else {//開發期間,走Console拋出FlutterError.dumpErrorToConsole(details);}};//2. runZonedGuarded監測整個用應用代碼異常 不使用FlutterError默認只能捕捉業務代碼異常runZonedGuarded(() {runApp(app);}, (e, s) => _reportError(e, s));}///通過接口上報異常_reportError(Object error, StackTrace s) {print('kReleaseMode:$kReleaseMode');print('catch error:$error');}
}
????????2. 監測頁面流暢性(幀率)
????????幀率監測在Flutter中通常通過在SchedulerBinding中注冊fps相關回調來實現。通常需要保留最近若干個FrameTiming的總耗時,計算其平均值,以消除不必要數據波動。
void start() {SchedulerBinding.instance.addTimingsCallback(_onReportTimings);
}
// 不需監聽時移除
void stop() {SchedulerBinding.instance.removeTimingsCallback(_onReportTimings);
}
void _onReportTimings(List<FrameTiming> timings) {// TODO
}
?????????3. 頁面顯示耗時(FCP)
? ? ? ? ?記錄頁面初始化和首次上屏時間,然后計算其時間差即可。
@overrideinitState() {super.initState();//1. 記錄頁面創建時間double startTime = time(0);//2.注冊首幀顯示時間回調WidgetsBinding.instance.addPostFrameCallback((timeStamp) {double endTime = time(0);print('WidgetsBinding Test-${(context as Element).size}');});
? ? ? ? 4.?頁面PV監測
? ? ? ? 頁面PV監測核心是檢測到頁面棧的變化,以便統計出頁面曝光次數。如果應用采用自定義導航框架,只需在導航框架正確位置添加埋點即可。若采用的是系統默認的導航框架,則可通過繼承NavigatorObserver,捕獲Navigator的didPush和didPop回調。
//導航棧的變化監聽
class MyNavigator extends NavigatorObserver{@overridevoid didPop(Route<dynamic> route, Route<dynamic> previousRoute) {super.didPop(route, previousRoute);var previousName = '';if (previousRoute == null) {previousName = 'null';}else {previousName = previousRoute.settings.name;}print('YM----->NavObserverDidPop--Current:' + route.settings.name + ' Previous:' + previousName);}@overridevoid didPush(Route<dynamic> route, Route<dynamic> previousRoute) {super.didPush(route, previousRoute);var previousName = '';if (previousRoute == null) {previousName = 'null';}else {previousName = previousRoute.settings.name;}print('YM-------NavObserverDidPush-Current:' + route.settings.name + ' Previous:' + previousName);}