## 一、统一模型 & 规范(细化) ### 1.1 SDKConfig 统一规范 所有端保持字段一致,命名按各端风格适配: jsonc ``` { "systemCode": "OA_APP", "endpointBaseUrl": "https://host/api/ExternalEventlogs", "clientType": 1, // 1 Android, 2 iOS, 3 Flutter "enableDebug": false, "batchSize": 20, // 单次最多上传条数 "flushInterval": 15, // 秒,定时 flush 间隔 "maxCacheSize": 5000, // 本地缓存最大事件条数 "maxRetryCount": 3, // 最大重试次数 "connectTimeout": 5000, // ms "readTimeout": 5000 // ms // 预留,将来可扩: // "globalTags": { "appVersion": "1.0.0", "channel": "official" } } ``` ### 1.2 Event 内部字段规范 统一内部 Event 类字段(各端自行建模): ts ``` class Event { String id; // 本地ID/主键 String systemCode; String eventType; UserInfo? userInfo; int clientType; int clientTimestamp; // ms String timestamp; // ISO8601 DeviceInfo deviceInfo; Map? eventParams; Map? customTags; int retryCount; // 已重试次数 DateTime createTime; } ``` ------ ## 二、Phase 1:可用 + 稳定(细化到类 & 表) ### 2.1 通用逻辑(跨端统一) #### 2.1.1 发送流程(时序) 1. App 调用 `Analytics.init(config)` 2. SDK: - 保存 config - 采集 DeviceInfo - 初始化 Storage - 启动定时任务(每 flushInterval 秒执行 flush) 3. App 调用 `Analytics.setUser(...)`(可多次) 4. App 调用 `Analytics.track(eventType, {...})`: - 构造 Event - 持久化入库 - 如果缓存条数 ≥ batchSize:启动一次 flush 5. flush 流程: - 从存储取前 `batchSize` 条事件; - 调用 `AddEventListLog`: - 成功:删除这些事件; - 网络错/5xx:更新 retryCount,重排队,按指数退避调度; - 4xx:记录日志,删除这些事件(视为「业务不可重试」)。 #### 2.1.2 本地表结构(推荐统一) SQLite 表 `events`: sql ``` CREATE TABLE events ( id INTEGER PRIMARY KEY AUTOINCREMENT, payload TEXT NOT NULL, -- 事件完整 JSON retry_count INTEGER NOT NULL DEFAULT 0, create_time INTEGER NOT NULL -- ms since epoch ); ``` 索引: sql ``` CREATE INDEX idx_events_create_time ON events(create_time); ``` > Flutter 可用 sqflite 按此结构实现。 ------ ### 2.2 Flutter SDK(Dart 独立实现) #### 2.2.1 目录结构建议 text ``` lib/ analytics.dart // 对外 Facade src/ config/ analytics_config.dart model/ event.dart user_info.dart device_info.dart storage/ event_storage.dart // 接口 sqflite_event_storage.dart network/ api_client.dart core/ analytics_core.dart // EventManager + Scheduler scheduler.dart util/ logger.dart time_util.dart ``` #### 2.2.2 关键类职责 - `Analytics`(facade) - 静态方法:`init / track / setUser / setDeviceInfo / flush / setDebug` - 内部持有单例 `AnalyticsCore` - `AnalyticsCore` - 字段: - `AnalyticsConfig _config` - `UserInfo? _user` - `DeviceInfo _device` - `EventStorage _storage` - `ApiClient _apiClient` - `Timer? _timer` - `bool _isFlushing` - 方法: - `init(config)` - `setUser` - `setDeviceInfo` - `track(...)` - `flush({bool force = false})` - `EventStorage` 接口 + `SqfliteEventStorage` 实现 - `Future insert(Event event)` - `Future> fetchBatch(int limit)` - `Future deleteByIds(List ids)` - `Future count()` - `Future trimToMaxSize(int maxSize)` - `ApiClient` - `Future sendBatch(List events)` - POST `/AddEventListLog`,Body 为数组; - 成功返回 true,失败 false 或抛异常。 - (可选)单条 `sendSingle(Event)` 作降级方案。 - `Scheduler` - 内含 `Timer.periodic`; - 每次 tick 调用 `core.flush()`; - 通过 `_isFlushing` 防并发。 #### 2.2.3 技术要求(Flutter) - 使用 `async/await`,所有 IO 非阻塞; - `Analytics` 所有对外 API 均返回 `Future`(init / track / flush)便于业务 await; - 避免 `Timer` 仍在运行却对象已销毁:在必要时提供 `dispose`(可选)。 ------ ### 2.3 Android SDK(Kotlin) #### 2.3.1 目录结构建议 text ``` com.company.analytics/ Analytics.kt // Facade config/ AnalyticsConfig.kt model/ Event.kt UserInfo.kt DeviceInfo.kt storage/ EventDao.kt EventDatabase.kt network/ ApiService.kt NetworkClient.kt core/ AnalyticsCore.kt FlushScheduler.kt util/ Logger.kt TimeUtil.kt ``` #### 2.3.2 关键实现要点 - Room 表结构: kotlin ``` @Entity(tableName = "events") data class EventEntity( @PrimaryKey(autoGenerate = true) val id: Long = 0, @ColumnInfo(name = "payload") val payload: String, @ColumnInfo(name = "retry_count") val retryCount: Int = 0, @ColumnInfo(name = "create_time") val createTime: Long = System.currentTimeMillis() ) ``` - DAO: kotlin ``` @Dao interface EventDao { @Insert suspend fun insert(entity: EventEntity) @Query("SELECT * FROM events ORDER BY create_time ASC LIMIT :limit") suspend fun fetchBatch(limit: Int): List @Query("DELETE FROM events WHERE id IN (:ids)") suspend fun deleteByIds(ids: List) @Query("SELECT COUNT(*) FROM events") suspend fun count(): Int @Query(""" DELETE FROM events WHERE id IN ( SELECT id FROM events ORDER BY create_time ASC LIMIT (SELECT MAX(0, COUNT(*) - :maxSize) FROM events) ) """) suspend fun trimToMaxSize(maxSize: Int) } ``` - 调度: - 使用 `CoroutineScope(SupervisorJob() + Dispatchers.IO)`; - `FlushScheduler` 用 `delay` 或 `TickerChannel` 实现周期任务; - 使用 `Mutex` 或 flag 控制“单一 flush”。 ------ ### 2.4 iOS SDK(Swift) #### 2.4.1 目录结构建议 text ``` AnalyticsSDK/ Analytics.swift // Facade Config/ AnalyticsConfig.swift Model/ Event.swift UserInfo.swift DeviceInfo.swift Storage/ EventStorage.swift SQLiteEventStorage.swift Network/ ApiClient.swift Core/ AnalyticsCore.swift FlushScheduler.swift Util/ Logger.swift TimeUtil.swift ``` #### 2.4.2 关键实现要点 - 存储: - 使用 SQLite(用 FMDB/GRDB 等封装,或自己写简单 wrapper); - 网络: - URLSession + Codable 序列化; - 定时: - `Timer.scheduledTimer` 或 `DispatchSourceTimer`; - 生命周期: - 订阅 `UIApplication` 通知,在进入后台前调用 `flush()`。 ------ ### 2.5 Phase 1 验收 checklist(落地用) - 三端提供初始化、用户设置、事件上报、flush API; - 本地缓存可持久化,多次启动数据不丢; - 断网 → 上报 → 恢复,事件能补发到后端; - 压测 10K 条事件,上报成功率可接受(> 99%,无 crash); - 业务方集成 Demo App 并通过功能测试。 ------ ## 三、Phase 2:配置化 + 校验 + 调试(细化) ### 3.1 新增数据结构 #### 3.1.1 维度配置缓存(本地) 以通用视角描述,三端类似: ts ``` class SystemDimInfo { SystemInfo systemInfo; List eventDefinitions; List tagDefinitions; DateTime lastFetchedAt; String? version; // 从后端 header 或 body 获得 } ``` - `EventDefinition` 来自 `systemEventTypes`: - `eventCode`, `eventName`, `description` - `TagDefinition` 来自 `systemCustonTas`: - `tag_name`, `tag_type`, `is_required`, `description` 本地可存储在: - Flutter:sqflite/hive 单独表/box; - Android:Room 新表 `config`; - iOS:UserDefaults / SQLite。 ### 3.2 ConfigManager / DimensionManager 职责: - 拉取 `GetSystemAllDimInfo(system_code)`; - 解析为 `SystemDimInfo`; - 序列化到本地; - 提供只读访问 API 给 Validator。 调用时机: - init 成功后异步拉取; - 间隔 N 小时(如 12 / 24h)自动刷新; - 提供 `forceRefresh()` 接口(仅 debug 使用)。 ### 3.3 Validator 详细逻辑 以伪代码描述: ts ``` validateEvent(event: Event): ValidationResult { let result = new ValidationResult() // 1. eventType 是否在配置中 if (!config.hasEvent(event.eventType)) { result.addError("UNKNOWN_EVENT_TYPE") } // 2. 校验必填 tag(customTags) let requiredTags = config.getRequiredTags() for (tag in requiredTags) { if (!event.customTags?.containsKey(tag.name)) { result.addWarning("MISSING_REQUIRED_TAG", tag.name) } else { // 3. 简单类型校验 if (!typeMatch(event.customTags[tag.name], tag.type)) { result.addWarning("TYPE_MISMATCH", tag.name) } } } return result } ``` - Debug 模式: - 所有 `errors` + `warnings` 打到日志; - 可选策略:有 error 的事件不发送。 - Release 模式: - 仍发送,但将错误信息 encode 到 `customTags._sdk_validation` 中。 ### 3.4 调试支持细化 #### 3.4.1 日志规范 统一日志前缀与级别: - `[AnalyticsSDK][DEBUG] ...` - `[AnalyticsSDK][ERROR] ...` 在 debug 打开时: - 打印: - 初始化配置; - 事件构造后的 JSON; - 每次发送的批次大小、结果状态码; - 校验结果(仅 debug)。 #### 3.4.2 Demo 调试面板(可选但推荐) Flutter / 原生各自 Demo App 中: - 提供一个 Debug 页面: - 显示当前缓存条数; - 最近 20 条事件简要信息(id、eventType、createTime、是否校验通过); - 按钮:`Flush Now`,调用 `Analytics.flush()`。 ------ ## 四、Phase 3:监控 + 动态策略 + 插件(细化) ### 4.1 SDK 自监控事件设计 定义一批内部保留事件(只你们自己分析用): - `SDK_METRICS_SEND`: - 字段: - `sentCount` - `failedCount` - `retryCount` - `avgLatencyMs` - `SDK_METRICS_QUEUE`: - 字段: - `queueSize` - `droppedEvents` 实现: - 在 SDK 内部维护计数器; - 每隔 M 分钟(如 10 分钟)封装成 Event,正常通过日志接口上报。 ### 4.2 策略配置结构 可通过扩展 `GetSystemAllDimInfo` 或另建接口下发 JSON,例如: jsonc ``` { "sdkStrategy": { "enabled": true, "defaultSampleRate": 1.0, "eventSettings": { "PAGE_VIEW": { "enabled": true, "sampleRate": 0.2 }, "DEBUG_EVENT": { "enabled": false, "sampleRate": 0.0 } } } } ``` SDK 行为: - 加载策略后: - `if !strategy.enabled`:`track` 直接返回,不做任何事情(紧急开关)。 - 查找具体 eventType 的策略: - `enabled=false` → 直接丢; - `sampleRate<1` → 按 sampleRate 随机采样(或使用 eventId hash)。 ### 4.3 插件机制设计 通用接口(以伪代码): ts ``` interface EventInterceptor { beforeSend(event: Event): Event | null | Promise afterSend(event: Event, result: SendResult): void | Promise } ``` - SDK 内部维护 `List`; - 在真正上传前,按顺序调用 `beforeSend`: - 任一返回 null → 事件被拦截,标记为丢弃; - 上传结束后,按顺序调用 `afterSend`。 错误隔离: ts ``` for interceptor in interceptors: try { event = interceptor.beforeSend(event) } catch (e) { log.warn("interceptor error: ", e) } ``` 示例内置插件: - DebugInterceptor: - beforeSend 打印事件 JSON(受 debug 开关控制); - CommonTagsInterceptor: - 自动在 customTags 注入 `_sdk_version`、`_platform` 等。 ------ ## 五、落地实施建议(简短) ### 5.1 Phase 1 任务拆分(多端并行) - 架构公共约定 & 协议定义(1~2 天) - Flutter SDK Phase 1 实现(约 5~10 个工作日) - Android SDK Phase 1 实现(约 5~10 天) - iOS SDK Phase 1 实现(约 5~10 天) - 后端联调 & Demo App 验证(3~5 天) ### 5.2 后续 Phase 2/3 可以按版本迭代 - v1.x:只做 Phase 1,快速在一个业务 App 落地; - v2.x:引入配置拉取 + 校验 + Debug 面板; - v3.x:按需要逐步加上策略控制 & 插件。