yx_tracking_flutter/2.Flutter 埋点 SDK 设计方案(独立 Da...

454 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Flutter 埋点 SDK 设计方案(独立 Dart 实现)
## 1. 概述
### 1.1 背景
为企业内部 OA / 教育等应用统一建设埋点能力,当前后端已提供日志上报接口:
- `GET /api/ExternalEventlogs/GetSystemAllDimInfo`
- `POST /api/ExternalEventlogs/AddEventListLog`
- `POST /api/ExternalEventlogs/AddEventLog`
需要基于上述接口,开发一个独立的 Flutter 埋点 SDKFlutter 运行环境使用,非纯 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": {
// 事件上下文
},
"customTags": {
// 业务维度
}
}
```
### 2.2 Flutter SDK 对外 Facade API
```dart
class Analytics {
static Future<void> init(AnalyticsConfig config);
static Future<void> track(
String eventType, {
Map<String, dynamic>? eventParams,
Map<String, dynamic>? customTags,
int? timestamp, // ms
});
static Future<void> setUser(UserInfo? userInfo);
static Future<void> setDeviceInfo(DeviceInfo deviceInfo);
static Future<void> 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/api/ExternalEventlogs
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<String, dynamic> 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<String, dynamic> 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<String, dynamic>? eventParams;
final Map<String, dynamic>? 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<String, dynamic> 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 任务。
- 事件上报:
- 构造 Eventsystem_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<void> init();
Future<int> insert(Event event);
Future<List<StoredEvent>> fetchBatch(int limit);
Future<void> deleteByIds(List<int> ids);
Future<int> count();
Future<void> trimToMaxSize(int maxSize);
Future<void> updateRetryCount(int id, int retryCount);
}
```
使用 `SqfliteEventStorage` 具体实现。
### 4.3 网络层 ApiClient
- 基于 `dio``http` 实现:
- `sendBatch(List<Event> 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<Event?> beforeSend(Event event) async => event;
Future<void> afterSend(Event event, bool success) async {}
}
```
-`AnalyticsCore` 中注册多个拦截器;
- flush 时在实际发送前后调用;
- 捕获拦截器内部异常,不影响主流程。
内置拦截器示例:
- `DebugInterceptor`:打印事件详细信息;
- `CommonTagsInterceptor`:为所有事件追加 `_sdk_version`、`_platform` 等 tag。