身份与生命周期
SDK 在记录事件时保存当时的用户和会话信息。用户随后登录或退出,不会改变已记录事件的归属。
身份字段
| 字段 | 含义与边界 |
|---|---|
anonymousId | SDK 分配的匿名旅程 ID,不代表物理设备唯一性 |
installationId | 原生安装作用域 ID;Android 清数据/卸载后通常变化,iOS Keychain 能否恢复取决于系统与存储条件 |
userId | 宿主认证成功后通过 identify 或 switchUser 传入的业务用户 ID |
sessionId | 分析会话 ID;超时、signOut、reset 或 switchUser 会轮换 |
groupId | group() 设置的组织上下文;退出或换账号时清除 |
tenantId 是服务端宿主提供的独立上下文,客户端的 group() 不会设置它。其他身份字段及取值限制见各端 API 参考。
SDK 默认可以创建匿名身份并记录最小范围事件。应用要求事前授权时,以 PENDING 初始化;获得授权后再调用 grantConsent()。授权前 SDK 不创建或恢复身份。详见授权与隐私。
Session 划分规则
- Web:默认 30 分钟无事件活动后,在下一条事件创建前轮转 Session;SPA 路由变化本身不强制切 Session。
- iOS / Android:默认 30 秒后台宽限。30 秒内返回保留 Session;超过宽限,返回前台或创建下一事件前轮换。即使没有后台信号,30 分钟无活动上限仍会触发轮转。生命周期观测
$sdk_lifecycle不表示 Session 边界;会话统计使用sessionId。 $app_end表示应用退入后台,不表示会话已经结束。
登录、退出与切换账号
| 操作 | 适用场景 | 关键语义 |
|---|---|---|
identify(userId) | 首次登录 | 将业务用户关联至当前匿名身份;已有其他用户时会拒绝调用。 |
signOut() | 退出登录 | 清除账号状态,并生成新的匿名身份和会话。 |
switchUser(next) | 直接切换至另一账号 | 清除旧账号状态,生成新的匿名身份并关联新用户。 |
clearUser() | 退出后仍需延续当前匿名旅程 | 清除账号状态,但保留当前匿名身份和会话。 |
reset() | 需要显式重置身份 | 清除身份作用域并生成新的匿名身份和会话。 |
同一设备换人时,请使用 switchUser(),不要对已登录账号直接调用 identify()。只有业务明确需要保留匿名连续性时才使用 clearUser()。
三端示例
typescript
const sdk = TrackBusinessSDK.create({ endpoint, projectKey });
await sdk.ready();
sdk.track('product_viewed', { sku: 'SKU-001' });
await sdk.identify('user_9527');
await sdk.group('org_1', { role: 'admin' });
await sdk.signOut(); // 默认安全退出
await sdk.switchUser('user_10086'); // 已知下一账号时可直接切换kotlin
val sdk = TrackBusinessSDK.create(applicationContext, endpoint, projectKey)
sdk.track("product_viewed", mapOf("sku" to "SKU-001"))
sdk.identify("user_9527")
sdk.group("org_1", mapOf("role" to "admin"))
sdk.signOut()
sdk.switchUser("user_10086")java
TrackBusinessSDK sdk = TrackBusinessSDK.create(context, endpoint, projectKey);
sdk.identify("user_9527");
sdk.signOut();
sdk.switchUser("user_10086");swift
let sdk = try TrackBusinessSDK.create(endpoint: endpoint, projectKey: projectKey)
sdk.track("product_viewed", properties: ["sku": .string("SKU-001")])
try sdk.identify(userId: "user_9527")
sdk.group("org_1", traits: ["role": .string("admin")])
sdk.signOut()
try sdk.switchUser(userId: "user_10086")不可变快照与离线事件
假设断网时产生事件 E1,随后用户登录并产生 E2:
text
E1 -> { eventId: e1, userId: null, anonymousId: a1, sessionId: s1 }
identify(U1)
E2 -> { eventId: e2, userId: U1, anonymousId: a1, sessionId: s1 }E1 在联网补发时仍是匿名事件;重试保持原 eventId 和原身份快照。clearUser / signOut 的系统事件也先用变更前状态入队,再执行状态迁移。
平台稳定性边界
| 场景 | 合同 |
|---|---|
| Web 同源刷新 | 已授权且存储可用时恢复;隐私模式/配额受限可能只在内存连续 |
| Web 跨子域 | 默认隔离,不自动共享 |
| iOS 进程重启 | 已授权时从 Keychain 尽力恢复;不保证卸载重装后恢复 |
| Android 进程重启 | 已授权且身份存储可用时恢复;清数据/卸载后通常创建新的安装标识 |
| 物理设备唯一 | 不支持;不得用匿名 ID 宣称设备唯一 |
clearLocalData() 比账号退出更强:清空 SDK 本地队列、身份和持久状态。denyConsent() 还会停止采集/调度,并使后续重新授权从新的身份开始。二者都不等于服务端用户删除请求;服务端数据主体权利需要独立 API 与审计流程。
各端方法签名见 Web API、Android API 和 iOS API。