f501a959f3
CI / flutter-gates (push) Successful in 1m9s
- 生产接线修复:app.dart 组装时传 analytics 实例给 ApiAuthRepository(_buildRepository),修复 M1 遗留的「生产环境 _analytics 恒为 null、挂接点空转」问题 - sessionId 生命周期:新建 SessionTracker (WidgetsBindingObserver),冷启动生成 UUIDv7、后台超 30 分钟换新、未超阈值沿用原值,不再每事件随机生成 - eventId 改 UUIDv7:对齐 13 号规范(uuid 包已在依赖,直接用 v7()),保留插入时间局部性 - appVersion 动态注入:package_info_plus(新增依赖)异步读取后 setAppVersion,不再硬编码 '1.0.0+1' - osVersion 动态读取:Platform.operatingSystemVersion 正则提取主版本(如 android-14),不再硬编码 - 队列顺手加固:上传失败批次重回队首而非整批丢弃(一行级缓解,分段持久化属 M2 第二波) 测试新增 9 例:session_tracker_test(5 例:冷启动/短后台/长后台/级联状态/连续幂等),analytics_service_test 补强 4 例(UUIDv7/sessionId 不再逐事件生成/appVersion 可注入/失败重回队列)。 验收对照(06 号报告 §5.1 六条):1✓ SessionTracker 新建、2✓ 三条语义、3✓ 同会话 sessionId 一致、4✓ sessionId 为 UUID 不持久化、5✓ 单测 3 例(实际 5 例)、6✓ 真机脚本(开发者手测)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
50 lines
1.9 KiB
Dart
50 lines
1.9 KiB
Dart
import 'package:flutter/widgets.dart';
|
||
import 'package:patbond_flutter/analytics/analytics_page_name.dart';
|
||
import 'package:patbond_flutter/analytics/page_view_tracker.dart';
|
||
|
||
/// 集中式 page_viewed 路由埋点(03 号评估 §3.2:NavigatorObserver 派生,
|
||
/// 页面零侵入;06 号报告 §5.2 验收 1/4)。
|
||
///
|
||
/// 只统计 [PageRoute](bottom sheet / dialog 是 PopupRoute,不计曝光);
|
||
/// 路由名不在 [AnalyticsPageName] 枚举内不上报(后端会整条 rejected,
|
||
/// 不白白消耗队列)。didPop 补报「回退后重新曝光的前一页」;弹回到
|
||
/// 无名根路由(认证状态机的 AnimatedSwitcher 宿主)时经 [resolveRootPage]
|
||
/// 解析当前根部页面。
|
||
class AnalyticsRouteObserver extends NavigatorObserver {
|
||
AnalyticsRouteObserver({required this.tracker, this.resolveRootPage});
|
||
|
||
final PageViewTracker tracker;
|
||
|
||
/// 根路由(无 RouteSettings.name)当前展示页的解析器,由 app.dart
|
||
/// 按认证状态与主壳当前 Tab 提供;返回 null 则不补报。
|
||
final AnalyticsPageName? Function()? resolveRootPage;
|
||
|
||
void _reportRoute(Route<dynamic>? route) {
|
||
if (route is! PageRoute) return;
|
||
final page = AnalyticsPageName.fromRouteName(route.settings.name);
|
||
if (page != null) tracker.report(page);
|
||
}
|
||
|
||
@override
|
||
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||
_reportRoute(route);
|
||
}
|
||
|
||
@override
|
||
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
|
||
_reportRoute(newRoute);
|
||
}
|
||
|
||
@override
|
||
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||
if (previousRoute is! PageRoute) return;
|
||
final page = AnalyticsPageName.fromRouteName(previousRoute.settings.name);
|
||
if (page != null) {
|
||
tracker.report(page);
|
||
} else if (previousRoute.isFirst) {
|
||
final rootPage = resolveRootPage?.call();
|
||
if (rootPage != null) tracker.report(rootPage);
|
||
}
|
||
}
|
||
}
|