qs_event_analytics

qs_event_analytics 是一个 Flutter 埋点插件,支持分别使用 Firebase Analytics、业务 API,或同时启用两个通道。

安装

dependencies:
  qs_event_analytics: ^1.1.5

本地调试:

dependencies:
  qs_event_analytics:
    path: ../qs_event_analytics

通道类型

类型 Firebase 业务 API
QsEventCategory.firebase 启用 禁用
QsEventCategory.api 禁用 启用
QsEventCategory.all 启用 启用

初始化配置必须与通道类型严格匹配。缺少必要配置或向单通道传入另一通道的配置时,initialize() 会抛出 ArgumentError

导入

import 'package:qs_event_analytics/qs_api_config.dart';
import 'package:qs_event_analytics/qs_api_event_type.dart';
import 'package:qs_event_analytics/qs_api_parameter_name_model.dart';
import 'package:qs_event_analytics/qs_event_analytics.dart';
import 'package:qs_event_analytics/qs_event_category.dart';
import 'package:qs_event_analytics/qs_firebase_config.dart';

初始化

仅 Firebase

业务项目需要先按 Firebase 官方要求配置 Android 和 iOS 工程。

await QsEventAnalytics.getInstance().initialize(
  category: QsEventCategory.firebase,
  firebaseConfig: const QsFirebaseConfig(),
);

如需显式传入 Firebase 配置:

await QsEventAnalytics.getInstance().initialize(
  category: QsEventCategory.firebase,
  firebaseConfig: QsFirebaseConfig(options: firebaseOptions),
);

仅业务 API

final apiConfig = QsApiConfig(
  userId: 'user_001',
  api: 'https://example.com/api/event/report',
  parameterNameModel: QsApiParameterNameModel(
    sessionId: 'sessionId',
    uuid: 'uuid',
    eventCode: 'eventCode',
    eventName: 'eventName',
    eventType: 'eventType',
    eventTime: 'eventTime',
    userIp: 'userIp',
    countryCode: 'countryCode',
    cityCode: 'cityCode',
    systemVersion: 'systemVersion',
    appVersion: 'appVersion',
    attrPage: 'attrPage',
    eventContent: 'eventContent',
    env: 'env',
  ),
  systemVersion: 'iOS 17.0',
  appVersion: '1.0.0',
  ignoreFailedEventCodes: const [],
);

await QsEventAnalytics.getInstance().initialize(
  category: QsEventCategory.api,
  apiConfig: apiConfig,
);

parameterNameModel 中的值是业务接口实际使用的 JSON 键名。

插件通过 POST JSON 请求 api。各字段的数据来源如下:

映射属性 请求值
sessionId 当前会话 ID
uuid userId
eventCode 事件编码
eventName 根据事件类型生成的事件名称
eventType 事件类型编码
eventTime 事件毫秒时间戳
userIp 当前 IP 地址,获取失败时为空字符串
countryCode 国家或地区名称,获取失败时为空字符串
cityCode 城市名称,获取失败时为空字符串
systemVersion systemVersion
appVersion appVersion
attrPage 所属页面,为 null 时发送空字符串
eventContent extra 序列化后的 JSON 字符串,未传时值为 null
env Debug/Profile 为 dev,Release 为 prd

响应 JSON 的 code 为数字 0 时调用 onSuccess,其他响应或请求异常调用 onError

同时启用

await QsEventAnalytics.getInstance().initialize(
  category: QsEventCategory.all,
  firebaseConfig: const QsFirebaseConfig(),
  apiConfig: apiConfig,
);

all 只表示两个通道均可用,不会自动把一次调用复制到另一个通道。调用方需要分别调用两个上报方法。

Firebase 上报

await QsEventAnalytics.getInstance().addFirebaseEvent(
  name: 'home_banner_click',
  parameters: {
    'banner_id': 'banner_001',
    'position': 1,
  },
);

addFirebaseEvent() 只接收 Firebase 需要的事件名和参数,并返回 Firebase 上报的 Future<void>。事件名超过 40 个字符时,Debug 模式会触发断言。

未初始化或当前 category 未启用 Firebase 时,该方法抛出 StateError

业务 API 上报

QsEventAnalytics.getInstance().addApiEvent(
  code: 'home_banner',
  name: '首页 Banner',
  type: QsApiEventType.click,
  belongPage: 'home',
  extra: const {
    'bannerId': 'banner_001',
    'position': '1',
  },
  onSuccess: () {
    debugPrint('API 埋点成功');
  },
  onError: () {
    debugPrint('API 埋点失败');
  },
);
参数 类型 说明
code String 事件编码
name String 事件名称
type QsApiEventType 业务事件类型
timestamp int? 可选毫秒时间戳,默认使用当前时间
belongPage String? 所属页面,允许为 null
extra Map<String, String>? 业务扩展参数
onSuccess VoidCallback 业务 API 返回 code == 0 时调用
onError VoidCallback 请求异常或业务 API 返回失败时调用

未初始化或当前 category 未启用 API 时,addApiEvent() 抛出 StateError

页面事件

使用 QsApiEventType.pageIn 上报新页面时,如果已有当前页面,插件会先自动补发上一页面的 pageOut,其时间戳为新事件时间戳减 1 毫秒。自动生成的页面退出事件只走业务 API,不会生成 Firebase 事件。

QsEventAnalytics.getInstance().addApiEvent(
  code: 'home',
  name: '首页',
  type: QsApiEventType.pageIn,
  belongPage: 'home',
  onSuccess: () {},
  onError: () {},
);

可以保存和恢复当前页面:

final analytics = QsEventAnalytics.getInstance();
final pageData = analytics.getCurrentPageData();

analytics.returnToCurrentPage(pageData: pageData);

returnToCurrentPage() 属于 API 通道行为,API 通道未启用时会抛出 StateError

事件类型

类型 业务接口编码 事件名称前缀
QsApiEventType.appIn in 原名称
QsApiEventType.appOut out 原名称
QsApiEventType.pageIn in 进入-【名称】
QsApiEventType.pageOut out 离开-【名称】
QsApiEventType.click click 点击-名称
QsApiEventType.valueChange click 值改变-名称
QsApiEventType.load load 加载-名称
QsApiEventType.show in 显示-【名称】
QsApiEventType.close out 关闭-【名称】
QsApiEventType.state load 状态-名称
QsApiEventType.error error 错误-名称

QsApiEventType 只用于业务 API。Firebase 事件名由调用方直接传给 addFirebaseEvent()

失败重试

API 上报失败时,未包含在 ignoreFailedEventCodes 中的事件会写入本地 SQLite 数据库。网络恢复后插件自动补发,成功后删除对应记录。

失败队列使用 qs_api_failed_event.db 数据库和 qs_api_failed_event_table 数据表,字段为 event_idevent_data。事件 JSON 使用 session_idevent_codeevent_nameevent_typeevent_timebelong_pageextra。旧 analytic_error.db 不再读取或迁移,也不会被插件主动删除。

失败队列仅属于 API 通道:

  • Firebase 事件不会写入失败队列;
  • 仅 Firebase 模式不会启动网络监听;
  • 当前 category 未启用 API 时不会执行队列补发。

会话 ID

final analytics = QsEventAnalytics.getInstance();

final sessionId = analytics.sessionId;
analytics.updateSessionId();

从旧接口迁移

旧版统一的 addEvent() 已移除:

  • Firebase 事件改用 addFirebaseEvent()
  • 业务接口事件改用 addApiEvent()
  • 原公开 recordEvent() 已改为插件内部私有实现;
  • 初始化参数分别放入 QsFirebaseConfigQsApiConfig
  • QsEventCategory.all 模式下需要分别调用两个上报方法。

注意事项

  • 必须先完成 initialize() 再调用上报方法。
  • 插件按单例设计,建议每次 App 运行只初始化一次。
  • API 通道会读取网络状态、IP 信息并使用本地数据库,请按业务合规要求完善隐私政策。
  • 当前失败补发没有互斥、去重、重试次数上限或退避策略,不能保证事件只发送一次。