yx_tracking_flutter/1.统一模型 & 规范(细化).md

12 KiB
Raw Blame History

一、统一模型 & 规范(细化)

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<String, dynamic>? eventParams;
  Map<String, dynamic>? 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 SDKDart 独立实现)

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 关键类职责

  • Analyticsfacade
    • 静态方法: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<void> insert(Event event)
    • Future<List<StoredEvent>> fetchBatch(int limit)
    • Future<void> deleteByIds(List<int> ids)
    • Future<int> count()
    • Future<void> trimToMaxSize(int maxSize)
  • ApiClient
    • Future<bool> sendBatch(List<Event> events)
      • POST /AddEventListLogBody 为数组;
      • 成功返回 true失败 false 或抛异常。
    • (可选)单条 sendSingle(Event) 作降级方案。
  • Scheduler
    • 内含 Timer.periodic
    • 每次 tick 调用 core.flush()
    • 通过 _isFlushing 防并发。

2.2.3 技术要求Flutter

  • 使用 async/await,所有 IO 非阻塞;
  • Analytics 所有对外 API 均返回 Futureinit / track / flush便于业务 await
  • 避免 Timer 仍在运行却对象已销毁:在必要时提供 dispose(可选)。

2.3 Android SDKKotlin

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<EventEntity>

  @Query("DELETE FROM events WHERE id IN (:ids)")
  suspend fun deleteByIds(ids: List<Long>)

  @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)
    • FlushSchedulerdelayTickerChannel 实现周期任务;
    • 使用 Mutex 或 flag 控制“单一 flush”。

2.4 iOS SDKSwift

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.scheduledTimerDispatchSourceTimer
  • 生命周期:
    • 订阅 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<EventDefinition> eventDefinitions;
  List<TagDefinition> tagDefinitions;
  DateTime lastFetchedAt;
  String? version;   // 从后端 header 或 body 获得
}
  • EventDefinition 来自 systemEventTypes
    • eventCode, eventName, description
  • TagDefinition 来自 systemCustonTas
    • tag_name, tag_type, is_required, description

本地可存储在:

  • Fluttersqflite/hive 单独表/box
  • AndroidRoom 新表 config;
  • iOSUserDefaults / 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. 校验必填 tagcustomTags
  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.enabledtrack 直接返回,不做任何事情(紧急开关)。
    • 查找具体 eventType 的策略:
      • enabled=false → 直接丢;
      • sampleRate<1 → 按 sampleRate 随机采样(或使用 eventId hash

4.3 插件机制设计

通用接口(以伪代码):

ts

interface EventInterceptor {
  beforeSend(event: Event): Event | null | Promise<Event | null>
  afterSend(event: Event, result: SendResult): void | Promise<void>
}
  • SDK 内部维护 List<EventInterceptor>
  • 在真正上传前,按顺序调用 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 任务拆分(多端并行)

  • 架构公共约定 & 协议定义12 天)
  • Flutter SDK Phase 1 实现(约 510 个工作日)
  • Android SDK Phase 1 实现(约 510 天)
  • iOS SDK Phase 1 实现(约 510 天)
  • 后端联调 & Demo App 验证35 天)

5.2 后续 Phase 2/3 可以按版本迭代

  • v1.x只做 Phase 1快速在一个业务 App 落地;
  • v2.x引入配置拉取 + 校验 + Debug 面板;
  • v3.x按需要逐步加上策略控制 & 插件。