帮你快速理解、总结文档立即下载

API 说明

最近更新时间:2026-11-06 09:10:01
本文档已由 AI 辅助审校
我的收藏
本文详细介绍用户体验监控 Android SDK 的各功能接口,帮助您更灵活、深度地使用 SDK。

初始化

SDK 通过 TDEM.init(config) 创建实例并自动开始采集,重复调用会返回同一实例;初始化后通过 TDEM.getInstance() 获取单例调用实例 API,未初始化时返回 null。
TDEM 上的静态方法共5个:
方法
用途
TDEM.init(config)
创建并启动 SDK,返回实例
TDEM.getInstance()
获取单例,未初始化返回 null
TDEM.addInitListener(listener)
注册启动结算监听,可在 init 之前调用
TDEM.removeInitListener(listener)
注销启动结算监听
TDEM.endLaunch()
业务就绪时手动封口启动测量
另有日志级别常量 TDEM.LEVEL_DEBUG / TDEM.LEVEL_INFO / TDEM.LEVEL_WARN / TDEM.LEVEL_ERROR 与版本常量 TDEMCore.SDK_VERSION。
Kotlin
Java
val tdem = TDEM.getInstance()
TDEM tdem = TDEM.getInstance(); // 未初始化时返回 null
启动结算可异步感知。TDEM.addInitListener 既可在 TDEM.init 之前注册,也可在之后注册;远程配置闸门落定后回调一次,若注册时决策已落定则立即回放结果。
Kotlin
Java
import com.tencent.tdem.core.TDEMInitListener

val listener = object : TDEMInitListener {
override fun onInitSettled(started: Boolean, remoteConfig: RemoteConfigResult?) {
// started:是否已进入采集态
// remoteConfig:本次决策使用的远程配置;拉取耗尽且无缓存时为 null
}
}

TDEM.addInitListener(listener) // 可在 TDEM.init 之前调用
TDEM.removeInitListener(listener) // 注销
import com.tencent.tdem.core.TDEMInitListener;

TDEMInitListener listener = (started, remoteConfig) -> {
// started:是否已进入采集态
// remoteConfig:本次决策使用的远程配置;拉取耗尽且无缓存时为 null
};

TDEM.addInitListener(listener);
TDEM.removeInitListener(listener);
回调覆盖三种结果:成功启动、远端关闭或未抽中、拉取耗尽;若 id / url 为空导致初始化被跳过,同样会以 started=false 回调。实例层另有 registerInitListener / unregisterInitListener,语义相同;接入方应统一使用上述入口层静态方法,避免 JVM 签名冲突。

自定义事件

Kotlin
Java
tdem?.track(
"button_click",
tags = mapOf("button_id" to "submit"),
properties = mapOf("page" to "/checkout"),
)
import java.util.HashMap;
import java.util.Map;

Map<String, String> tags = new HashMap<>();
tags.put("button_id", "submit");
Map<String, Object> properties = new HashMap<>();
properties.put("page", "/checkout");

tdem.track("button_click", tags, properties);

自定义测速

Kotlin
Java
// 直接上报耗时(毫秒)
tdem?.measure("api_latency", 320, tags = mapOf("api" to "/user/info"))

// 或使用计时器
tdem?.startMeasure("render")
// ... 执行操作 ...
val duration = tdem?.endMeasure("render") // 返回耗时(ms),未找到 start 返回 -1
// 直接上报耗时(毫秒)
Map<String, String> tags = new HashMap<>();
tags.put("api", "/user/info");
tdem.measure("api_latency", 320, tags, new HashMap<String, Object>());

// 或使用计时器
tdem.startMeasure("render");
// ... 执行操作 ...
long duration = tdem.endMeasure("render"); // 返回耗时(ms),未找到 start 返回 -1
measure / endMeasure 支持省略末尾可选参数的短重载,因此 Java 侧也可写成 tdem.measure("api_latency", 320) 或 tdem.endMeasure("render")。

异常上报

Kotlin
Java
try {
riskyOperation()
} catch (e: Exception) {
tdem?.captureException(e, tags = mapOf("module" to "payment"))
}
Map<String, Object> crashTags = new HashMap<>();
crashTags.put("module", "payment");
try {
riskyOperation();
} catch (Exception e) {
tdem.captureException(e, crashTags);
}

captureException 只有 (Throwable, Map<String, Object>) 一种签名,没有 level 参数,也没有可省略参数的重载;Java 侧直接传异常与标签即可。

用户标识管理

Kotlin
Java
tdem?.setUser("user-456") // 设置用户
tdem?.clearUser() // 清除用户
tdem.setUser("user-456"); // 设置用户
tdem.clearUser(); // 清除用户

Compose 组件标记

Compose 场景下的组件标记依赖 com.tencent.tdem:tdem-behavior-compose(版本与 tdem 保持一致)。该库提供三种标记入口,可按需组合使用:
本节示例均为 Kotlin。@Composable 函数只能由 Kotlin 编译器产出,下列示例都写在 Composable 作用域内,SDK 也未提供等价的 Java 入口;Java 项目使用这些能力时,这部分代码同样需要写在 Kotlin 文件中。
import com.tencent.tdem.behavior.compose.tdemTag
import com.tencent.tdem.behavior.compose.TDEMTraced
import com.tencent.tdem.behavior.compose.withTDEMPageTracking

// 1. 给单个 Composable 打标签
Button(modifier = Modifier.tdemTag("buy_button")) { Text("购买") }

// 2. 包裹一段 Composable,为整个子树生成一个可定位节点
TDEMTraced("CheckoutBody") {
CheckoutContent()
}

// 3. 让 NavHost 的页面流转自动上报,enabled 默认 true
val navController = rememberNavController().withTDEMPageTracking()
三种入口的作用与说明如下:
方法
说明
Modifier.tdemTag(tag)
为单个组件写入 TDEMTag 语义属性,该值会作为组件的元素标识进入点击、长按事件
TDEMTraced(tag, modifier) { }
用 Layout 包裹子树并打标签,适用于一组控件共用同一个标识
NavHostController.withTDEMPageTracking(enabled)
追踪 NavHost 的页面流转并上报 page_view;enabled 默认 true,传 false 可临时关闭
引入 Kotlin 编译器插件后无需手动调用 tdemTag:插件会在编译期为每个 @Composable 函数自动注入标签,取值为该函数名。androidx、com.tencent.tdem 包下的函数与非 @Composable 函数不注入;excludeComposeModifiers = true 时整块 Compose 标签注入都不生效(标签与 Modifier 都不注入),等价于关闭本能力。需要覆盖自动生成的名称时,可再手动调用 tdemTag 显式指定。
注意: Compose 的页面流转有两条路径:withTDEMPageTracking() 在代码中显式包裹,tdem-plugin 的 instrumentComposeNavigation 在编译期自动插桩。两者只需启用其一,同时开启不会重复上报,但会多一次无谓的注册。

设备标识管理

Kotlin
Java
tdem?.setDeviceId("device-abc") // 设置设备标识,由宿主提供
tdem?.clearDeviceId() // 清除设备标识,回落 not_set
tdem.setDeviceId("device-abc"); // 设置设备标识,由宿主提供
tdem.clearDeviceId(); // 清除设备标识,回落 not_set
设备标识由业务侧提供,SDK 不会自行读取 ANDROID_ID 等系统标识;未设置或传空白时上报字面量 not_set。也可在 TDEMConfiguration 的 deviceId 中于初始化时一并设置。

全局标签管理

Kotlin
Java
tdem?.setTags(mapOf("role" to "admin", "team" to "dev")) // 设置/追加标签
tdem?.removeTags(listOf("team")) // 移除指定标签
tdem?.clearTags() // 清空所有标签
Map<String, Object> tags = new HashMap<>();
tags.put("role", "admin");
tags.put("team", "dev");

tdem.setTags(tags); // 设置/追加标签
tdem.removeTags(Arrays.asList("team")); // 移除指定标签
tdem.clearTags(); // 清空所有标签

页面管理

Kotlin
Java
// 手动逻辑页(LIFO,覆盖自动 Activity/Fragment/Compose 页)
tdem?.startPage("checkout")
tdem?.leavePage() // LIFO pop,栈空时幂等 no-op

// 替换当前逻辑页并发 page_view(navigation_type=replace,RN SPA 切页用)
tdem?.setPage("/modal/confirm", pageTitle = "确认弹窗")

// 三参:额外指定本次页面浏览的 viewId(不传则每次 setPage 自动生成新的 UUID)
tdem?.setPage("/modal/confirm", pageTitle = "确认弹窗", viewId = "confirm_dialog_v1")
// 手动逻辑页(LIFO,覆盖自动 Activity/Fragment/Compose 页)
tdem.startPage("checkout");
tdem.leavePage(); // LIFO pop,栈空时幂等 no-op

// 替换当前逻辑页并发 page_view(navigation_type=replace,RN SPA 切页用)
tdem.setPage("/modal/confirm", "确认弹窗");

// 三参:额外指定本次页面浏览的 viewId(不传则每次 setPage 自动生成新的 UUID)
tdem.setPage("/modal/confirm", "确认弹窗", "confirm_dialog_v1");
viewId 是该逻辑页的页面浏览实例标识。SDK 在每次页面切换时生成新的 viewId,并在上报事件的顶层 view_id 字段带上它,用于标识该事件发生在哪一次页面浏览中。setPage 传入 viewId 时直接采用传入值(需自行保证唯一性);不传则由 SDK 自动生成,通常无需干预。

上下文与状态查询

除写入接口外,SDK 也提供读取当前运行状态的接口,便于接入自检与问题定位。
Kotlin
Java
tdem?.getTags() // 当前全局标签快照,Map<String, Any>
tdem?.currentPageUrl // 当前页面标识
tdem?.currentViewId // 当前页面浏览实例 ID,与事件 view_id 同源
tdem?.getCurrentSessionId() // 当前会话 ID,会话未就绪返回 ""
tdem?.getCurrentReplayId() // 当前回放 ID,未启用回放返回 ""
tdem?.userId // 当前用户标识,未设置返回 null
tdem?.deviceId // 当前设备标识,未设置返回 not_set
tdem?.initialized // SDK 是否已进入采集态
import java.util.Map;

Map<String, Object> tags = tdem.getTags();
String pageUrl = tdem.getCurrentPageUrl();
String viewId = tdem.getCurrentViewId();
String sessionId = tdem.getCurrentSessionId();
String replayId = tdem.getCurrentReplayId();
String userId = tdem.getUserId();
String deviceId = tdem.getDeviceId();
getCurrentSessionId() 在会话尚未就绪时返回空串;
getCurrentReplayId() 在未启用回放时返回空串;
currentPageUrl 的取值为「手动页面栈顶 > 自动识别的 Activity / Fragment / Compose 页 > unknown」。
currentViewId 即事件上报中的 view_id,随页面切换刷新;当前无有效页面(如处于后台或尚未识别到页面)时返回空串。
resolveReplayLink(timestampMs) 按事件时间戳反查所属回放段,返回回放 ID 与相对段起点的偏移毫秒数,无命中窗口时返回 null。返回对象位于内部包(com.tencent.tdem.internal.v6$a),当前版本的访问器为混淆后的 b()(回放 ID)与 a()(偏移毫秒数),属性名可能随版本变化,取值时建议以方法调用为准:
Kotlin
Java
val link = tdem?.resolveReplayLink(eventTimeMs)
if (link != null) {
println("replay=${link.b()}, offset=${link.a()}ms") // b()=回放 ID,a()=偏移毫秒数
}
// 返回类型是 Kotlin 嵌套类(内部包),Java 源码里无法写出它的类名,
// 用 var 让编译器推断;Java 8 项目可声明为 Object,但那样拿不到 b() / a()。
var link = tdem.resolveReplayLink(eventTimeMs);
if (link != null) {
System.out.println("replay=" + link.b() + ", offset=" + link.a() + "ms"); // b()=回放 ID,a()=偏移毫秒数
}
以下两个接口属进阶用法,一般由插件或桥接层使用:
isPluginEnabled(pluginEnabled, remoteEnabled) 做插件挂载的两级决策(远程配置明确关闭时返回 false,否则取本地配置)。
putContextField(key, value) 向 Protocol v2 批量上下文追加自定义字段(key 空白或 value 为空时忽略)。

挣扎事件上报

Kotlin
Java
// 业务主动上报自定义挣扎事件(无需理解或填写 owner)
tdem?.trackStruggle(
"payment_declined",
severity = TDEMStruggleSeverity.HIGH, // LOW(1) / MEDIUM(3) / HIGH(5),默认 MEDIUM
properties = mapOf("reason" to "risk_rejected", "retry_count" to 2),
tags = mapOf("channel" to "checkout"),
)
// 业务主动上报自定义挣扎事件(无需理解或填写 owner)
Map<String, Object> props = new HashMap<>();
props.put("reason", "risk_rejected");
props.put("retry_count", 2);
Map<String, String> tags = new HashMap<>();
tags.put("channel", "checkout");

tdem.trackStruggle(
"payment_declined",
TDEMStruggleSeverity.HIGH, // LOW(1) / MEDIUM(3) / HIGH(5),默认 MEDIUM
props,
tags
);

原始事件上报

Kotlin
Java
// 直接上报 TDEMEvent 格式的事件(高级用法,SDK 会自动补齐 page_url、session_id 与 tags)
tdem?.reportTDEMEvent(
TDEMEvent(
eventType = EventType.CUSTOM,
eventCategory = EventCategory.CUSTOM,
pageUrl = currentPageUrl,
sessionId = tdem.getCurrentSessionId(),
data = JSONObject().put("event_name", "my_event"),
)
)
// 直接上报 TDEMEvent 格式的事件(高级用法,SDK 会自动补齐 page_url、session_id 与 tags)
// 注意:eventId 在 Kotlin 有默认值(自动生成);Java 主构造器不生成,必须自己传非空值,
// 传空串会原样上报成空的 event_id。
try {
JSONObject data = new JSONObject();
data.put("event_name", "my_event");

tdem.reportTDEMEvent(new TDEMEvent(
UUID.randomUUID().toString(), // eventId:Java 侧必须显式给
EventType.CUSTOM,
EventCategory.CUSTOM,
System.currentTimeMillis(),
"", // pageUrl 留空则取当前页面
"", // sessionId 留空则取当前会话
data,
"", // replayId
"" // viewId
));
} catch (JSONException e) {
// JSONObject.put 是受检异常
}

启动封口

业务就绪时结束启动测量。需先配置 LaunchPluginConfig(manualEndEnabled = true):
Kotlin
Java
TDEM.endLaunch()
TDEM.endLaunch();

配置修改与销毁

Kotlin
Java
tdem?.setUser("new-user") // 动态修改用户标识
tdem?.destroy() // 销毁实例
tdem.setUser("new-user"); // 动态修改用户标识
tdem.destroy(); // 销毁实例

版本与日志

SDK 版本号以 TDEMCore.SDK_VERSION 为准,日志级别在初始化时通过 TDEMConfiguration.Builder.logLevel(...) 设定:
Kotlin
Java
import com.tencent.tdem.TDEM
import com.tencent.tdem.TDEMConfiguration
import com.tencent.tdem.core.TDEMCore

TDEMCore.SDK_VERSION // 当前 SDK 版本号,如 "0.1.25"
TDEMConfiguration.Builder(this).logLevel(TDEM.LEVEL_WARN) // 日志级别,默认 WARN
import com.tencent.tdem.TDEM;
import com.tencent.tdem.TDEMConfiguration;
import com.tencent.tdem.core.TDEMCore;

String version = TDEMCore.SDK_VERSION; // 当前 SDK 版本号,如 "0.1.25"
new TDEMConfiguration.Builder(this).logLevel(TDEM.LEVEL_WARN); // 日志级别,默认 WARN
日志级别常量 TDEM.LEVEL_DEBUG / LEVEL_INFO / LEVEL_WARN / LEVEL_ERROR 可直接用于 Builder.logLevel(...),初始化时下推 native。全模块日志统一使用 TDEM-Android 作为 Logcat tag,模块名只出现在日志正文中;tag 不可配置,SDK 也未提供独立的日志开关接口。

环境枚举

用于标识应用部署所属环境,区分不同环境的数据上报、日志采集与监控策略,枚举定义如下:
production:生产环境。
development:开发环境。
gray:灰度环境。
pre:预发布环境。
daily:日发布环境。
local:本地环境。
test:测试环境。
others:其他环境(未知值归一于此)。