13 KiB
13 KiB
一、总体目标与边界
1.1 目标
基于现有后端接口,建设一套统一的埋点 SDK,覆盖:
- 技术栈:
- Flutter:独立纯 Dart SDK
- Android:原生 Kotlin SDK
- iOS:原生 Swift SDK
- 对齐后端接口:
GET /api/ExternalEventlogs/GetSystemAllDimInfoPOST /api/ExternalEventlogs/AddEventListLogPOST /api/ExternalEventlogs/AddEventLog
- 三阶段演进:
- Phase 1:可用性 + 安全稳定性
- Phase 2:可维护性 + 配置化 + 调试
- Phase 3:可观测性 + 动态策略 + 插件化
不绑定具体业务逻辑,但要能支持 OA、教育等各类场景。
1.2 统一事件数据模型
请求结构(与后端对齐)
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、buttonId、url…
},
"customTags": {
// 扩展维度,业务可自定义
}
}
统一对外 API 设计(跨三端)
(伪接口,三端风格尽量保持一致)
ts
class Analytics {
static init(config: SDKConfig): void | Future<void>
static track(
eventType: string,
options?: {
eventParams?: Map<string, any>
customTags?: Map<string, any>
timestamp?: number // 毫秒级 client 时间,可不传
}
): void | Future<void>
static setUser(userInfo: UserInfo | null): void | Future<void>
static setDeviceInfo(deviceInfo: DeviceInfo): void | Future<void>
static flush(): void | Future<void>
static setDebug(enabled: boolean): void
}
SDKConfig 关键字段(统一):
systemCode: stringendpointBaseUrl: string(如https://host/api/ExternalEventlogs)clientType: int(统一约定:1=Android,2=iOS,3=Flutter)enableDebug: booleanbatchSize: int(默认 20)flushInterval: int(秒,默认 15)maxCacheSize: int(默认 5000)maxRetryCount: int(默认 3)connectTimeout,readTimeout
二、整体架构设计(通用视角)
SDK 内部统一分层:
- API 层(Facade)
- 暴露
init / track / flush / setUser / setDebug - 做参数校验、线程切换(原生)。
- 暴露
- EventManager(事件管理层)
- 构造标准事件对象(填充 system_code、userInfo、deviceInfo、时间)。
- 写入本地队列;触发上传调度。
- Storage(存储层)
- 事件持久化(SQLite / 本地 KV)。
- 控制队列长度、过期清理。
- NetworkClient(网络层)
- 封装调用:
AddEventListLog(优先)、AddEventLog(可选降级)。 - 统一超时、重试、错误处理。
- 封装调用:
- Config / DimensionManager(配置 & 维度)
- 管理 SDKConfig。
- Phase 2+:拉取
GetSystemAllDimInfo,存本地。
- Validator / Debug(校验 & 调试)
- Phase 2+:基于配置做事件参数校验。
- 统一 debug 日志输出。
- Interceptors / Plugins(插件层)
- Phase 3:对事件发送前后提供 Hook。
三、三端实现策略
3.1 Flutter 独立 SDK(纯 Dart)
- 语言:Dart
- 存储:推荐
sqflite(SQLite)或hive(KV):events(id, payload_json, retry_count, create_time)
- 网络:
dio或http包 - 调度:
Timer.periodic实现定时 flush- 控制并发:用一个「上传中」标志避免并发多次 flush
- 生命周期:
- SDK 暴露
flush(); - 应用可在自身生命周期(如
WidgetsBindingObserver或 Router)中调用。
- SDK 暴露
3.2 Android SDK
- 语言:Kotlin(对 Java 兼容)
- 存储:Room 或 SQLite 封装
- 网络:OkHttp + Retrofit
- 线程:Kotlin Coroutines + 单一上传协程
- 生命周期:
ProcessLifecycleOwner监听前后台 → 后台前触发flush
3.3 iOS SDK
- 语言:Swift(暴露 ObjC 兼容 API)
- 存储:SQLite 或 Core Data 轻量封装
- 网络:URLSession
- 生命周期:监听
willResignActive/didEnterBackground调用flush
四、三阶段规划(含架构与验收)
Phase 1:可用性 + 安全稳定性
4.1 目标
- 提供稳定、可用的基础事件采集 & 批量上报能力。
- 不影响业务性能和体验。
- 基本安全(HTTPS,预留签名扩展)。
4.2 能力范围
- 初始化
- 校验并保存
SDKConfig; - 自动采集
DeviceInfo; - 初始化本地存储;
- 启动定时 flush 调度(根据 flushInterval)。
- 校验并保存
- 事件写入(track)
- 检查 SDK 是否已 init;
- 构造 Event:
system_codefrom configeventTypefrom 调用userInfofromsetUserclientTypefrom configclientTimestamp= 当前毫秒时间戳timestamp= ISO8601 字符串deviceInfofrom 初始化采集eventParams、customTagsfrom 调用
- 事件入内存队列 + 异步持久化保存。
- 缓存与发送策略
- 存储:
- SQLite / KV + 索引;
- 最大缓存条数:
maxCacheSize,超限则删除最旧事件。
- 发送:
- 定时器触发 flush;
- 队列长度 >=
batchSize可立即 flush; - 调用
AddEventListLog批量上传; - 如后端明确不支持,可选降级
AddEventLog。
- 重试:
- 网络错误或 5xx 重试,最多
maxRetryCount,指数退避; - 4xx 视为业务失败,不重试,直接丢弃该批,并记录错误(日志)。
- 网络错误或 5xx 重试,最多
- 存储:
- 安全与稳定
- endpoint 必须为 HTTPS;
- 预留请求 header 扩展(签名 / 时间戳 / nonce)。
- 所有 IO 和网络在后台线程 / async,不阻塞 UI;
- 所有异常在 SDK 内部捕获,不向上抛出导致崩溃。
4.3 开发要求
通用:
- 核心逻辑单元测试覆盖率 ≥ 80%(事件构造、缓存、上传、重试)。
- 使用统一的日志前缀(例如
[AnalyticsSDK])。 - API 文档齐全,含参数说明和示例代码。
Flutter:
- 不引入过重依赖,确保兼容常见 Flutter stable 版本;
- 高频 track 时(例如 10 次/秒)主 Isolate 无明显卡顿。
Android:
- 支持主流 Android 版本(按照公司基线,例如 API 21+);
- 在 debug 版开启详细日志,release 版关闭。
iOS:
- 支持主流 iOS 版本(例如 iOS 12+);
- 保证在 App 退后台 / 杀进程前能尽可能 flush。
4.4 Phase 1 验收标准
功能:
- 三端均可:
init → setUser → track → flush全流程成功; - 离线:
- 断网时事件成功写入本地;
- 恢复网络后自动/手动 flush,可在后端查看到补发数据;
- 批量:
- 实际调用
AddEventListLog; - 后端数据结构与约定一致(字段正确)。
- 实际调用
稳定:
- 连续调用 track 1 万次以内无崩溃;
- 事件缓存满时按预期丢弃最旧数据,不影响业务。
安全:
- 所有请求通过 HTTPS;
- 默认不输出包含 userInfo 的敏感日志(除非显式 enableDebug)。
文档:
- 各端接入指南(集成、初始化、上报示例);
- 一份基础 FAQ(常见错误、排查方式)。
Phase 2:可维护性 + 配置化 + 调试能力
5.1 目标
- 降低埋点维护成本;
- 支持通过后端配置管理事件和维度;
- 提供调试和校验工具,提高埋点正确率。
5.2 能力范围
- 利用
GetSystemAllDimInfo下发配置
- SDK 在 init 后或定期调用:
- 获取
systemInfo、systemEventTypes、systemCustonTas;
- 获取
- 转换成本地配置对象,缓存到本地(带 version / lastModified):
ts
type EventDefinition = {
eventCode: string
eventName: string
description?: string
}
type TagDefinition = {
tagName: string
tagType: string // string/int/bool/enum
isRequired: boolean
description?: string
}
- 失败不影响事件发送(降级为无配置模式)。
- 事件校验
- 在
track时(主要在 debug 模式启用):- 校验
eventType是否存在于systemEventTypes; - 使用
systemCustonTas检查:- 必填 tag 是否存在;
- 类型是否匹配(尝试容错转换)。
- 校验
- 错误处理:
- Debug 模式:
- 在日志中详细打印:未注册事件、缺失字段、类型错误;
- 可配置:是否禁止发送这类事件。
- Release 模式:
- 仍发送,但在
customTags中附加:_sdk_invalid_event_sdk_missing_tags_sdk_type_error_fields
- 仍发送,但在
- Debug 模式:
- 调试工具
- 日志级:
setDebug(true)时:- 打印每条事件的 JSON;
- 打印发送结果(状态码、错误内容)。
- Demo 内调试页面(建议):
- 支持:
- 查看缓存事件数量 / 最近 N 条事件摘要;
- 按钮触发 flush。
- 支持:
- 队列与策略优化(基本)
- 事件过期时间(例如默认 7 天);
- 网络状态感知(原生):
- Wi-Fi 下更高频 / 大批次;
- 蜂窝网络下减少频率 / 批量。
5.3 开发要求
- 新增模块:
ConfigManager:拉取与缓存后端维度配置;Validator:统一事件校验逻辑。
- 兼容 Phase 1:
- 未取到配置时,一切行为回退到 Phase 1 模式;
- 增加测试:
- 事件存在 / 不存在;
- 必填字段缺失;
- 类型错误时的行为。
5.4 Phase 2 验收标准
功能:
- 初始化后,可以成功调用
GetSystemAllDimInfo并本地缓存; - 在 debug 模式下:
- 未配置的
eventType调用时有明确日志提示; - 缺失必填 tag / 类型错误能被检测并打印提示。
- 未配置的
调试体验:
- 开发可以在本地:
- 看到完整事件 JSON;
- 根据提示迅速发现埋点错漏。
可维护性:
- 后端新增事件配置(systemEventTypes 中新增)后,不发版即可在客户端调用新事件;
- 对关键事件,可以通过配置 + SDK 校验,显著减少埋点错误。
Phase 3:可观测性 + 动态策略 + 插件化
6.1 目标
- 让 SDK 自身「可被监控、可被远程控制」;
- 支持高级使用场景:采样、动态开关、插件扩展。
6.2 能力范围
- SDK 自身监控埋点
- 内部采集 SDK 运行指标(作为特殊事件上报):
- 发送成功计数 / 失败计数 / 重试次数;
- 平均延迟;
- 队列当前长度 / 溢出丢弃数;
- 周期性上报(如每 N 分钟一次)。
- 动态策略控制
- 通过配置(可在
GetSystemAllDimInfo扩展,或单独接口)下发策略,如:
jsonc
{
"enabled": true,
"eventSettings": {
"EVENT_A": { "enabled": true, "sampleRate": 1.0 },
"EVENT_B": { "enabled": false, "sampleRate": 0.0 },
"EVENT_C": { "enabled": true, "sampleRate": 0.1 }
}
}
- SDK 在
track时:- 若事件被标记
enabled=false→ 直接丢弃; - 若
sampleRate < 1→ 按采样率丢弃部分事件(哈希或随机)。
- 若事件被标记
- 插件 / 拦截器机制
- 接口示例(通用设计):
ts
interface EventInterceptor {
beforeSend(event: Event): Event | null | Promise<Event | null>
afterSend(event: Event, result: SendResult): void | Promise<void>
}
- SDK 提供:
registerInterceptor(interceptor)/addInterceptor方法;- 内置拦截器:debug 打印、公共字段填充等。
典型用途:
- 业务统一追加自定义
customTags(如租户 ID、业务线 ID); - 将部分发送失败事件写入本地日志,便于问题排查。
- 版本管理
- 事件级 schemaVersion 预留:
- 在
customTags或eventParams中加入_schema_version。
- 在
- SDK 版本上报:
- 每条事件默认携带
_sdk_version和_platform,便于后端统计版本分布。
- 每条事件默认携带
6.3 开发要求
- 性能:
- 插件链路运行开销可控(单条事件处理在毫秒级以内);
- 隔离:
- 单个插件抛出的异常不会影响主流程和其他插件;
- 文档:
- 清晰说明策略配置字段及含义;
- 插件开发 & 使用指南。
6.4 Phase 3 验收标准
- 自监控:
- 后端可以查看 SDK 的发送成功率、失败率、队列长度等;
- 动态控制:
- 通过配置关闭某个 eventType 后,客户端不再上报该事件;
- 调整 sampleRate 后,事件量按预期变化;
- 插件:
- 样例插件能实现:
- 自动附加业务 tag;
- 记录失败事件到本地日志。
- 样例插件能实现:
这版方案已经:
- 明确:Flutter 为独立纯 Dart SDK,与 Android/iOS 平行;
- 统一:三端对外 API、数据结构、阶段目标和验收标准;
- 预留:维度配置、校验、动态策略、插件机制的扩展空间。