本文介绍接入用户体验监控 iOS SDK 后,如何验证各监控能力的数据上报是否成功。
前提条件
崩溃、卡顿、启动、网络、挣扎检测、设备信息默认开启,无需额外配置;用户行为(
behavior.enabled)与 Session Replay(replay.enabled)默认关闭,需在初始化时显式开启。崩溃为100% 上报、不支持采样,其余能力均支持采样。建议在接入期间将所有采样率调为1.0(如
replay.sessionSampleRate = 1.0),方便验证数据上报;接入完成后再按需调整。步骤1:检查上报请求
初始化后,SDK 会发出下列请求(Session Replay 默认关闭,开启后才有回放上报)。HTTP 状态码 2xx 且响应体中
code 为 0 时视为成功:端点 | 内容 |
POST {url}/api/v1/config | 远程配置,仅在返回启用时才挂载各监控模块 |
POST {url}/api/v1/collect/events | 标准事件(崩溃 / 卡顿 / 启动 / 网络 / 行为 / 挣扎 / 自定义事件等) |
POST {url}/api/v1/collect/replay | Session Replay 录屏数据 |
url 填站点根地址即可,SDK 会自行拼接路径,无需手动补 /api/v1。SDK 自身与采集服务之间的同源请求会被自动排除,不会产生递归上报。步骤2:验证各监控能力
崩溃监控
说明:
崩溃捕获依赖系统的 signal 监听接口,若 App 中接入其他具备类似能力的 SDK 或存在监听 signal 的逻辑,可能影响崩溃捕获成功率。请确保 SDK 初始化在其他监听逻辑注册之后,以减少对崩溃捕获的影响。
崩溃事件为 100% 上报,不参与采样,与其他监控能力相互独立。SDK 捕获范围覆盖以下四类异常:
Mach 异常(
kscrash_mach)。信号异常(
kscrash_signal),如 SIGSEGV、SIGABRT。OC 异常(
kscrash_nsexception),即未被捕获的 NSException。C++ 异常(
kscrash_cpp)。崩溃发生前若存在关联的点击行为记录,SDK 会额外派生一条
error_click 挣扎事件,用于定位「点击后崩溃」场景。模拟异常
初始化完成后,可通过模拟 OC 异常、信号异常、C++ 异常来验证崩溃上报:
// 模拟 OC 异常let data: Any = NSArray(object: "Hello World")let _ = (data as! NSDictionary).object(forKey: "")// 模拟信号异常abort()// 模拟 C++ 异常// throw "Something went wrong"
// 模拟 OC 异常id data = [NSArray arrayWithObject:@"Hello World"];[(NSDictionary *)data objectForKey:@""];// 模拟信号异常abort();// 模拟 C++ 异常(需在 .mm 文件中)// throw std::runtime_error("Something went wrong");
崩溃发生后,异常需在第二次启动 App 时才完成上报,且上报可能存在延时。建议触发异常后重启 App,然后在 Xcode 控制台搜索关键字 TDEM 进行查看。
卡顿监控
可通过在主线程执行异常耗时任务模拟卡顿:
// 模拟卡顿(主线程阻塞)while true {// 空循环阻塞主线程}
卡顿上报后,在 Xcode。 控制台搜索关键字 TDEM 进行查看。
卡顿监控包含两类事件:
lag_detected:主线程卡顿,判定阈值由 stallThresholdMs 控制,默认 1000ms,取值需大于 0 且小于 5000ms,否则初始化会失败(stall_invalid_configuration)。no_response:主线程无响应,阈值固定 5000ms,由 SDK 内部写死,接入方不可修改。两类事件都会采集代表性堆栈与掉帧指标。上方示例的死循环会触发
no_response;若要触发 lag_detected,阻塞时长需超过 stallThresholdMs 且低于 5000ms:// 模拟卡顿:在主线程阻塞 3 秒Thread.sleep(forTimeInterval: 3)
// 模拟卡顿:在主线程阻塞 3 秒[NSThread sleepForTimeInterval:3];
Android 侧的 ANR 监控在 iOS 上由主线程无响应检测覆盖,iOS 无独立的 ANR 事件类型。
启动监控
启动监控默认开启,时间戳由
TDEMLaunchBridge 在进程启动阶段记录,早于 SDK 初始化执行,不依赖 TDEM.start 的调用时机。iOS 启动类型共3种:
first:首次安装后的第一次启动。cold:进程被杀死后重新启动。warm:从后台切回,且后台停留超过 180 秒。说明:
慢启动阈值由 SDK 内部维护(冷启动 4000ms / 温启动 2000ms),接入方不可修改。
默认在首个页面绘制后自动封口并上报事件
app_launch。若配置 configuration.launch.manualEndEnabled = true,则改为等待业务调用 TDEM.endLaunch();若 10 秒内未调用,SDK 会回落到首次绘制时刻封口,避免启动数据丢失。上报耗时由
process_to_sdk_ms、sdk_to_did_finish_launching_ms、did_finish_launching_to_first_draw_ms 三段组成,duration 为三者之和。验证方式:冷启动 App 后观察 Xcode 控制台中的启动日志。
let configuration = TDEMConfiguration(id: "<project-key>",url: URL(string: "https://dem.rumt-zh.com")!)configuration.launch.manualEndEnabled = true // 置 true 后需在首个页面绘制后调用 TDEM.endLaunch()TDEM.start(configuration: configuration)
TDEMConfiguration *configuration =[[TDEMConfiguration alloc] initWithId:@"<project-key>"url:[NSURL URLWithString:@"https://dem.rumt-zh.com"]];configuration.launch.manualEndEnabled = YES; // 置 YES 后需在首个页面绘制后调用 [TDEM endLaunch][TDEM startWithConfiguration:configuration];
网络监控
开启网络监控(
network.enabled = true)后,正常发起任意 HTTP 请求即可验证网络请求数据的采集与上报,慢请求(超过 slowThresholdMs 阈值)会单独标记。采集的事件类型分三类:api_call:成功的 HTTP 请求。api_error:失败的 HTTP 请求,error_type 细分为 dns / connect / tls / timeout / read_write / cancelled / other。sse_call:SSE 长连接。默认仅上报慢成功与错误 / 取消的请求,如需上报全部成功请求,可将
reportAllSuccessfulRequests 置为 true。configuration.network.enabled = trueconfiguration.network.slowThresholdMs = 1000configuration.network.reportAllSuccessfulRequests = falseconfiguration.network.allowedHosts = ["api.example.com"] // 非空时仅采集命中白名单的请求configuration.network.deniedHosts = [] // 仅在 allowedHosts 为空时生效configuration.network.additionalSensitiveHeaderNames = ["x-custom-token"]
configuration.network.enabled = YES;configuration.network.slowThresholdMs = 1000;configuration.network.reportAllSuccessfulRequests = NO;configuration.network.allowedHosts = @[ @"api.example.com" ]; // 非空时仅采集命中白名单的请求configuration.network.deniedHosts = @[]; // 仅在 allowedHosts 为空时生效configuration.network.additionalSensitiveHeaderNames = @[ @"x-custom-token" ];
行为监控与会话回放
行为监控需显式开启
behavior.enabled = true,开启后在 App 内进行页面跳转、点击等操作即可验证埋点上报。开启行为监控后,SDK 采集以下事件:
页面:
page_view触摸:
click / long_press / scroll输入:
form_focus / form_blur / form_change / form_submit手动逻辑页可通过
startPage / leavePage 声明,二者需成对、按 LIFO 顺序调用:TDEM.startPage(pageID: "checkout")// ... 页面逻辑 ...TDEM.leavePage()
[TDEM startPageWithPageID:@"checkout"];// ... 页面逻辑 ...[TDEM leavePage];
会话回放需显式开启
replay.enabled = true,建议临时将 sessionSampleRate 调为1.0。let configuration = TDEMConfiguration(id: "<project-key>",url: URL(string: "https://dem.rumt-zh.com")!)configuration.behavior.enabled = trueconfiguration.replay.enabled = trueconfiguration.replay.sessionSampleRate = 1.0 // 验证期间建议置 1.0TDEM.start(configuration: configuration)
TDEMConfiguration *configuration =[[TDEMConfiguration alloc] initWithId:@"<project-key>"url:[NSURL URLWithString:@"https://dem.rumt-zh.com"]];configuration.behavior.enabled = YES;configuration.replay.enabled = YES;configuration.replay.sessionSampleRate = 1.0; // 验证期间建议置 1.0[TDEM startWithConfiguration:configuration];
采样是双通道:
sessionSampleRate(默认0.10)决定常规会话是否被录制;未命中时若 errorSampleRate(默认 1.0)大于 0,SDK 会进入缓冲模式,在发生错误时冲刷并上报(缓冲窗口默认30秒)。控制台下发的远程配置
replay_sample_rate(0 - 100)会覆盖本地 sessionSampleRate。因此「开启了回放却没看到数据」不一定是接入失败,需要依次确认:本地 enabled 已开启、控制台远程配置已启用回放、且会话被采样命中。录制清晰度由
quality 控制,可选 low(默认)/ medium / high。iOS 默认遮罩输入类控件(
UITextField / UITextView)与显式标记为敏感的视图,maskAllText / maskAllImages 默认均为 false。如需对自动识别覆盖不到的控件(如订单金额、收货地址这类字面无语义特征的文案)主动声明为敏感,可调用
TDEMPrivacyMetadata:// 标记为敏感:行为监控不采集该控件文本,Session Replay 遮罩该控件及其子树TDEMPrivacyMetadata.setSensitive(true, for: orderAmountLabel)// 只调 Session Replay 遮罩,不影响文本采集TDEMPrivacyMetadata.setReplayMasking(.masked, for: qrCodeView)TDEMPrivacyMetadata.setReplayMasking(.inherit, for: qrCodeView) // 恢复默认判定
// 标记为敏感:行为监控不采集该控件文本,Session Replay 遮罩该控件及其子树[TDEMPrivacyMetadata setSensitive:YES forView:orderAmountLabel];// 只调 Session Replay 遮罩,不影响文本采集[TDEMPrivacyMetadata setReplayMasking:TDEMReplayMaskingMasked forView:qrCodeView];[TDEMPrivacyMetadata setReplayMasking:TDEMReplayMaskingInherit forView:qrCodeView]; // 恢复默认判定
标记父容器时,Session Replay 会把标记向下传递(等价于遮罩整棵子树);行为监控只判定被标记的控件本身,子控件文本仍会被采集,需逐个标记。
验证方式:开启 Session Replay 后操作 App,在控制台的回放列表查看会话录像,并确认被标记的控件在录像中已遮罩。
挣扎检测
挣扎检测默认开启,产出5类子事件:
rage_click:同一元素1秒内连续点击5次。dead_click:点击后 3 秒内既无页面跳转也无接口调用,判定为无响应。error_click:点击后 3 秒内出现接口错误或 JS / Promise 错误。long_focus_time:输入控件持续聚焦超过20秒。back_forward:10 秒内连续返回3次。说明:
规则阈值由 SDK 内部维护,接入方不可修改。
需要注意的是,默认配置下通常只有
back_forward 能被触发。click / form_focus / form_blur 等事件由用户行为监控(behavior.enabled)产生,而行为监控默认关闭,因此依赖这些事件源的 rage_click / dead_click / error_click / long_focus_time 会静默失效。要完整验证挣扎检测,需要同时开启行为监控:let configuration = TDEMConfiguration(id: "<project-key>",url: URL(string: "https://dem.rumt-zh.com")!)configuration.behavior.enabled = true // 必需:提供点击 / 表单事件源TDEM.start(configuration: configuration)
TDEMConfiguration *configuration =[[TDEMConfiguration alloc] initWithId:@"<project-key>"url:[NSURL URLWithString:@"https://dem.rumt-zh.com"]];configuration.behavior.enabled = YES; // 必需:提供点击 / 表单事件源[TDEM startWithConfiguration:configuration];
说明:
back_forward 消费的是页面事件,而页面事件有不受行为监控开关影响的来源(startPage / setPage / leavePage),因此它单独可用。如需精确忽略某个控件的 dead click 判定,可调用
TDEMBehaviorMetadata.setDeadClickIgnored(_:for:)。验证方式:连点同一按钮5次以上触发
rage_click,或在10秒内连续返回3次触发 back_forward,随后在控制台的挣扎事件页查看。设备信息
设备信息随每条事件的上下文一并上报,SDK 在事件批次中填充
session_id / app_version / environment / user_id / device_type / os / os_version / screen_resolution / device_id 字段。其中 SDK 版本号位于批次的 sdk 对象(sdk.name / sdk.version)中。验证方式:在控制台打开任一事件的详情,确认事件上下文中的上述字段已填充。
步骤3:主动上报(可选)
除自动采集外,SDK 提供下列主动上报接口,均为
TDEM 的类方法,可直接调用。// 自定义事件TDEM.track("order_submit", tags: ["channel": "app"], properties: ["amount": 99])// 自定义测速:可直接传耗时,也可 start / end 成对使用TDEM.measure("api_latency", duration: 320, tags: ["api": "/user/info"], properties: [:])TDEM.startMeasure("render")TDEM.endMeasure("render", tags: ["step": "pay"], properties: [:]) // 未调用 startMeasure 时为 no-op// 上报已捕获异常(未导致崩溃的业务异常)TDEM.captureException(error, tags: ["module": "payment"], properties: [:])// 自定义挣扎TDEM.trackStruggle("custom_struggle", severity: .high, properties: ["element": "buy_btn"], tags: [:])
// 自定义事件[TDEM trackWithName:@"order_submit" tags:@{ @"channel": @"app" } properties:@{ @"amount": @99 }];// 自定义测速:可直接传耗时,也可 start / end 成对使用[TDEM measureWithName:@"api_latency" duration:320 tags:@{ @"api": @"/user/info" }];[TDEM startMeasureWithName:@"render"];[TDEM endMeasureWithName:@"render" tags:@{ @"step": @"pay" }]; // 未调用 startMeasure 时为 no-op// 上报已捕获异常(未导致崩溃的业务异常)[TDEM captureExceptionWithError:error tags:@{ @"module": @"payment" }];// 自定义挣扎[TDEM trackStruggleWithName:@"custom_struggle" severity:TDEMStruggleSeverityHigh properties:@{ @"element": @"buy_btn" }];
用户标识、设备标识与全局标签:
TDEM.setUser("user-456") // 设置用户标识,用于用户维度聚合TDEM.clearUser() // 清除用户标识TDEM.setDeviceId("device-abc") // 设置设备标识,由宿主提供TDEM.clearDeviceId() // 清除设备标识,回落 not_setTDEM.setTags(["role": "admin", "team": "dev"]) // 设置 / 追加标签TDEM.removeTags(["team"]) // 移除指定标签TDEM.clearTags() // 清空所有标签
[TDEM setUser:@"user-456"]; // 设置用户标识,用于用户维度聚合[TDEM clearUser]; // 清除用户标识[TDEM setDeviceId:@"device-abc"]; // 设置设备标识,由宿主提供[TDEM clearDeviceId]; // 清除设备标识,回落 not_set[TDEM setTags:@{ @"role": @"admin", @"team": @"dev" }]; // 设置 / 追加标签[TDEM removeTags:@[ @"team" ]]; // 移除指定标签[TDEM clearTags]; // 清空所有标签
生命周期与缓冲控制:
TDEM.endLaunch() // 手动结束启动(需先设 launch.manualEndEnabled = true)TDEM.flush() // 立即冲刷缓冲事件TDEM.stop() // 停止 SDK
[TDEM endLaunch]; // 手动结束启动(需先设 launch.manualEndEnabled = YES),返回 BOOL[TDEM flush]; // 立即冲刷缓冲事件[TDEM stop]; // 停止 SDK
如需上报业务日志,可改用
TDEM.track 自定义事件承载。步骤4:检查数据上报
iOS SDK 的日志通过
NSLog 输出,格式为 [TDEM][<category>] <code>。诊断日志默认关闭,需在初始化时设置 configuration.debug = true 才会输出。在 Xcode 的 Console 中按
TDEM 过滤即可:[TDEM][transport] acknowledged[TDEM][behavior] page_view_persist_failed[TDEM][lifecycle] launch_sealed
也可以打开 macOS 的控制台 App,选择对应的模拟器 / 真机设备后按
TDEM 过滤。