Skip to content

38 · 埋点与行为分析 ​

一句话定位:埋点是"产品的事实数据层",对应前端接入 GA/友盟等统计 SDK。本篇讲 Flutter 里埋点怎么设计、怎么和 Riverpod 打通、怎么保证不漏不重,以及国内隐私合规的红线。

开篇速览 ​

问题答案
前端对应物GA / 友盟 / 自研埋点 SDK,dataLayer.push 事件队列
核心概念事件总线 + 埋点 SDK + 批量上报 + 离线补偿
最常见的错埋点散落在每个页面手写,字段不统一,漏埋难查
一句话红线埋点不是"加一行日志",而是有 schema、有去重、有隐私边界的数据管道

代码来源说明:HaierEnergy 当前 lib/ 有零散日志上报痕迹,但无统一埋点框架。 本篇按"通用方案 + 项目建议"撰写。


一、埋点的四类事件 ​

类型例子关注指标
页面(PV/UV)进入设备详情页访问量、停留时长
点击/行为点击"下发参数"点击率、转化率
曝光列表项可见曝光率、有效曝光
异常/性能接口失败、卡顿错误率、可用性(与 20 篇 联动)

二、埋点架构:事件总线 + 采集层 ​

埋点代码不该散落在业务里。推荐分层:

dart
// 1. 埋点模型(统一 schema,禁止各页面自定义字段名)
class AnalyticsEvent {
  final String name;          // 如 device_detail_view
  final Map<String, Object?> params; // 规范化字段
  final DateTime occurredAt;
}

// 2. 事件总线:业务方只管发事件,不管上报细节
class AnalyticsBus {
  void track(String name, {Map<String, Object?> params = const {}}) {
    _controller.add(AnalyticsEvent(name: name, params: params));
  }
}

2.1 与 Riverpod 打通 ​

建议把埋点封装成 Provider,业务代码一行调用:

dart
final analyticsProvider = Provider<AnalyticsBus>((ref) => AnalyticsBus());

// 业务侧
ref.read(analyticsProvider).track('device_param_send', params: {
  'device_id': deviceId,
  'result': result ? 'ok' : 'fail',
});

为什么用 Provider 而不是全局单例:可注入、可测试、可替换成 mock(配合 19 篇 的 ProviderContainer.overrides)。


三、批量上报与离线补偿 ​

高频事件不能一条一条发 HTTP:

手段作用
批量聚合攒 N 条或 T 秒再上报
本地缓存队列网络失败先落盘,恢复后补发
去重相同事件在短时间内只算一次
采样超大流量场景按比例抽(配置化)
dart
// 伪代码:批量上报器
class BatchReporter {
  final _buffer = <AnalyticsEvent>[];

  void enqueue(AnalyticsEvent event) {
    _buffer.add(event);
    if (_buffer.length >= 20) flush();
  }

  Future<void> flush() async {
    final batch = List.of(_buffer);
    _buffer.clear();
    await api.report(batch); // 失败时写回缓存,下次重试
  }
}

四、关键设计点 ​

4.1 字段规范化 ​

所有事件统一携带 app_version、os、device_id、session_id、ts。禁止同一个语义在不同页面叫不同字段名。

4.2 会话(Session) ​

一次会话要有唯一 session_id,前后台切换超过阈值(如 30 分钟)切新会话。埋点数据没有会话概念就无法算漏斗。

4.3 曝光埋点的坑 ​

曝光 ≠ 进入页面。列表项进入可视区才算曝光:

dart
// 用 VisibilityDetector 或自定义滚动回调,判定可见后再上报
VisibilityDetector(
  key: const ValueKey('device_card_1'),
  onVisibilityChanged: (info) {
    if (info.visibleFraction > 0.5 && !_reported) {
      analytics.track('device_card_expose', params: {'device_id': id});
    }
  },
  child: deviceCard,
)

五、隐私合规红线(必读) ​

要求做法
告知与授权首次启动弹隐私协议,用户同意后才初始化埋点
最小化采集只采业务必要字段,不采无关通讯录/位置
标识脱敏device_id 用匿名化标识,不绑定可识别个人信息
可关闭提供"关闭个性化统计"开关,关闭后立即停采
跨境合规数据出境需评估(个人信息保护法 / GDPR)

埋点 SDK 的初始化时机也要合规:很多 SDK 在 main() 里直接初始化,会违反"先授权后采集"。


六、项目落地建议 ​

  1. 先定事件字典(Excel/文档维护),再写代码,避免字段发散;
  2. 埋点抽象成 AnalyticsBus Provider,业务只发事件不碰上报;
  3. 曝光/点击/页面三类高频事件必须用批量 + 去重;
  4. 隐私授权流程走通后再初始化第三方 SDK;
  5. 与 20 篇 的性能/异常数据共用一套上报通道,减少维护面。

动手练习 ​

  1. 设计 AnalyticsBus + BatchReporter 的最小实现(含批量、失败缓存、去重);
  2. 给设备列表页加曝光埋点,用 Widget test 验证"滚动到可见才上报";
  3. 写一份 10 行以内的事件字典表(页面/点击/曝光/异常各 2~3 条)。

自检清单 ​

  • [ ] 能说出四类事件与各自关注指标
  • [ ] 能用事件总线 + Provider 统一埋点入口
  • [ ] 知道批量上报、去重、离线补偿的作用
  • [ ] 知道曝光 ≠ 进入页面,会用可见性判定
  • [ ] 知道隐私合规的最小动作(授权 / 最小化 / 可关闭)

常见误区 ​

  • "埋点就是 console.log":无 schema、无去重、无缓存,数据没法用;
  • "曝光就是进页面":列表项要滚动到可视区才算曝光;
  • "直接初始化第三方 SDK":先授权后采集,顺序反了就是合规事故;
  • "一条一条发请求":高频事件会把请求打爆,必须批量。

相关文档 ​