# Flutter 埋点 SDK 设计方案(独立 Dart 实现) ## 1. 概述 ### 1.1 背景 为企业内部 OA / 教育等应用统一建设埋点能力,当前后端已提供日志上报接口: - `GET /api/ExternalEventlogs/GetSystemAllDimInfo` - `POST /api/ExternalEventlogs/AddEventListLog` - `POST /api/ExternalEventlogs/AddEventLog` 需要基于上述接口,开发一个独立的 Flutter 埋点 SDK(Flutter 运行环境使用,非纯 Dart 运行时),并规划三阶段能力演进。 ### 1.2 目标 - 开发 Flutter 独立埋点 SDK 包(例如:`company_analytics_sdk`)。 - 提供统一的初始化、事件上报、缓存与批量上报能力。 - 三阶段演进目标: - Phase 1:可用性 + 安全稳定性。 - Phase 2:可维护性 + 配置化 + 调试。 - Phase 3:可观测性 + 动态策略 + 插件化。 --- ## 2. 统一模型与对外 API ### 2.1 统一事件数据结构(对齐后端) ```jsonc { "system_code": "string", "eventType": "string", "userInfo": { "userId": 0, "userName": "string", "account": "string" }, "clientType": 1, "clientTimestamp": 0, "timestamp": "2026-01-26T08:29:44.734Z", "deviceInfo": { "os": "string", "model": "string", "screenResolution": "string" }, "eventParams": { "Page": "string", "Url": "string", "ButtonId": "string" }, "customTags": { // 业务维度 } } ``` ### 2.2 Flutter SDK 对外 Facade API ```dart class Analytics { static Future init(AnalyticsConfig config); static Future track( String eventType, { Map? eventParams, Map? customTags, int? timestamp, // ms }); static Future setUser(UserInfo? userInfo); static Future setDeviceInfo(DeviceInfo deviceInfo); static Future flush(); // Phase 1: Lifecycle static void bindLifecycleObserver({bool flushOnBackground = true, bool flushOnDetached = true}); static void unbindLifecycleObserver(); static void setDebug(bool enabled); // Phase 3 static void addInterceptor(AnalyticsInterceptor interceptor); } ``` ### 2.3 SDKConfig 统一规范 ```dart class AnalyticsConfig { final String systemCode; final String endpointBaseUrl; // https://host(仅基础 host) final int clientType; // 1=Android, 2=iOS, 3=Flutter final bool enableDebug; final int batchSize; // 默认 20 final int flushInterval; // 秒,默认 15 final int maxCacheSize; // 默认 5000 final int maxRetryCount; // 默认 3 final Duration connectTimeout; // 默认 5s final Duration readTimeout; // 默认 5s const AnalyticsConfig({ required this.systemCode, required this.endpointBaseUrl, required this.clientType, this.enableDebug = false, this.batchSize = 20, this.flushInterval = 15, this.maxCacheSize = 5000, this.maxRetryCount = 3, this.connectTimeout = const Duration(seconds: 5), this.readTimeout = const Duration(seconds: 5), this.useIsolateStorage = true, // 默认开启 Isolate(仅 Flutter 环境可用) this.maxEventAge = const Duration(days: 7), // 事件过期时间 }); } ``` --- ## 3. 包结构与模块划分 ### 3.1 目录结构(建议) ```text lib/ company_analytics.dart // 对外 Facade(唯一入口) src/ config/ analytics_config.dart // SDKConfig config_manager.dart // (Phase 2+) 维度 & 策略配置 model/ event.dart // Event, StoredEvent user_info.dart device_info.dart system_dim_info.dart // (Phase 2+) SystemInfo, EventDefinition, TagDefinition storage/ event_storage.dart // 抽象接口 sqflite_event_storage.dart // SQLite 实现 isolate_event_storage.dart // (New) Isolate 异步存储包装 network/ api_client.dart // 与后端 API 通信 http_client.dart // 封装 Dio / http core/ analytics_core.dart // 主逻辑:init/track/flush scheduler.dart // 定时任务 & 并发控制 validator.dart // (Phase 2+) 事件校验 interceptors.dart // (Phase 3) 插件接口 & 管理 util/ logger.dart // 日志 & debug 控制 time_util.dart // 时间格式化 device_util.dart // 获取 os/model/screenResolution id_generator.dart // 本地 eventId 生成 ``` ### 3.2 核心模型 UserInfo: ```dart class UserInfo { final int? userId; final String? userName; final String? account; const UserInfo({this.userId, this.userName, this.account}); Map toJson() => { 'userId': userId, 'userName': userName, 'account': account, }..removeWhere((k, v) => v == null); } ``` DeviceInfo: ```dart class DeviceInfo { final String os; final String model; final String screenResolution; const DeviceInfo({ required this.os, required this.model, required this.screenResolution, }); Map toJson() => { 'os': os, 'model': model, 'screenResolution': screenResolution, }; } ``` Event: ```dart class Event { final String systemCode; final String eventType; final UserInfo? userInfo; final int clientType; final int clientTimestamp; final String timestamp; final DeviceInfo deviceInfo; final Map? eventParams; final Map? customTags; final DateTime createTime; final int retryCount; Event({ required this.systemCode, required this.eventType, required this.userInfo, required this.clientType, required this.clientTimestamp, required this.timestamp, required this.deviceInfo, required this.eventParams, required this.customTags, required this.createTime, this.retryCount = 0, }); Map toJson() => { 'system_code': systemCode, 'eventType': eventType, 'userInfo': userInfo?.toJson(), 'clientType': clientType, 'clientTimestamp': clientTimestamp, 'timestamp': timestamp, 'deviceInfo': deviceInfo.toJson(), 'eventParams': eventParams, 'customTags': customTags, }; } ``` StoredEvent: ```dart class StoredEvent { final int id; final Event event; final int retryCount; final DateTime createTime; StoredEvent({ required this.id, required this.event, required this.retryCount, required this.createTime, }); } ``` --- ## 4. Phase 1:可用性 + 安全稳定性 ### 4.1 功能范围 - SDK 初始化: - 校验 `AnalyticsConfig`; - 自动采集 `DeviceInfo`; - 初始化本地 SQLite 存储; - 启动定时 flush 任务。 - 事件上报: - 构造 Event(system_code、userInfo、deviceInfo、时间戳等); - 异步写入本地队列(SQLite)。 - 批量上传: - 定时 & 条数触发 flush; - 调用 `POST /AddEventListLog`; - 处理重试 / 失败 / 删除等逻辑。 - 安全: - endpoint 强制 HTTPS; - 预留 header 扩展(签名等)。 ### 4.2 本地存储设计(Sqflite) 表结构: ```sql CREATE TABLE events ( id INTEGER PRIMARY KEY AUTOINCREMENT, payload TEXT NOT NULL, retry_count INTEGER NOT NULL DEFAULT 0, create_time INTEGER NOT NULL ); CREATE INDEX idx_events_create_time ON events(create_time); ``` 接口:`EventStorage` ```dart abstract class EventStorage { Future init(); Future insert(Event event); Future> fetchBatch(int limit); Future deleteByIds(List ids); Future count(); Future trimToMaxSize(int maxSize); Future updateRetryCount(int id, int retryCount); } ``` 使用 `SqfliteEventStorage` 具体实现。 ### 4.3 网络层 ApiClient - 基于 `dio` 或 `http` 实现: - `sendBatch(List events)` 调用 `/AddEventListLog`。 - 超时控制:使用 `config.connectTimeout` / `readTimeout`。 ### 4.4 核心逻辑 AnalyticsCore 职责: - 保存配置、用户状态、设备信息。 - `track`:构造 Event、写入存储、触发 flush。 - `flush`:从本地取批量事件,调用 ApiClient,上报异常处理和重试。 关键点: - 使用 `_isFlushing` 标志防止并发 flush; - 使用 `Scheduler`(Timer.periodic)实现周期 flush; - 所有 IO 调用 async/await,避免阻塞 UI。 ### 4.5 Phase 1 验收标准(Flutter) - 功能: - Demo 中完成初始化、用户设置、事件上报、flush; - 断网时事件写入本地,恢复网络后自动/手动 flush 成功。 - 稳定性: - 高频 `track`(10 次/秒,5 分钟)无 crash、无明显卡顿。 - 安全: - 所有请求走 HTTPS; - 默认不打印 userInfo 等敏感数据(除非 debug=true)。 - 文档: - 接入文档 + 示例代码。 --- ## 5. Phase 2:配置化 + 校验 + 调试 ### 5.1 配置下发(GetSystemAllDimInfo) - Flutter SDK 调用: - `GET /GetSystemAllDimInfo?system_code=xxx` - 解析为: - `SystemInfo` - `EventDefinition` 列表(来自 `systemEventTypes`) - `TagDefinition` 列表(来自 `systemCustonTas`) 本地缓存为 `SystemDimInfo`(可存 SQLite / hive / SharedPreferences)。 ### 5.2 ConfigManager - 负责: - 首次 init 后拉取配置; - 定期刷新; - 提供当前配置给 Validator 使用。 ### 5.3 Validator 事件校验 - 校验点: - `eventType` 是否在配置中存在; - 必填 tag(来自 `TagDefinition.isRequired`)是否存在于 `customTags`; - 简单类型检查(int/bool/string)。 策略: - Debug 模式: - 日志详细提示未知事件、缺失字段、类型错误; - 可配置是否阻断发送。 - Release 模式: - 不阻断,错误信息写入 `customTags._sdk_validation`。 ### 5.4 调试能力 - 日志: - `Logger` 控制 debug 开关; - 打印事件 JSON、发送结果、校验结果。 - Demo 调试界面(推荐): - 展示缓存事件数量 / 最近 N 条; - 提供“立即 flush”按钮。 --- ## 6. Phase 3:可观测性 + 策略 + 插件 ### 6.1 SDK 自监控 - 内部统计: - 发送成功次数 / 失败次数; - 重试次数; - 队列长度 / 溢出丢弃个数。 - 周期上报为特殊事件(如 `SDK_METRICS_SEND`/`SDK_METRICS_QUEUE`)。 ### 6.2 动态策略控制 - 从配置中下发策略字段,例如: ```jsonc { "sdkStrategy": { "enabled": true, "defaultSampleRate": 1.0, "eventSettings": { "PAGE_VIEW": { "enabled": true, "sampleRate": 0.2 }, "DEBUG_EVENT": { "enabled": false, "sampleRate": 0.0 } } } } ``` - `track` 时根据策略: - 全局关停:直接丢弃全部事件; - 单事件关闭:丢弃该 eventType; - 按 sampleRate 采样丢弃部分事件。 ### 6.3 插件(拦截器)机制 接口示例: ```dart abstract class AnalyticsInterceptor { Future beforeSend(Event event) async => event; Future afterSend(Event event, bool success) async {} } ``` - 在 `AnalyticsCore` 中注册多个拦截器; - flush 时在实际发送前后调用; - 捕获拦截器内部异常,不影响主流程。 内置拦截器示例: - `DebugInterceptor`:打印事件详细信息; - `CommonTagsInterceptor`:为所有事件追加 `_sdk_version`、`_platform` 等 tag。