Cocos Creator 会话重放(实验性)¶
本文说明 Cocos Creator Session Replay 初始化、Camera 选择、性能参数、触摸隐私和节点隐私规则。
实验性能力
Cocos Creator 会话重放目前为实验性能力,API、平台兼容性和回放效果可能在后续版本中调整。建议先在测试环境评估隐私、性能和回放完整性,再决定是否用于生产环境。
前置条件¶
Session Replay 依赖:
- Android 或 iOS 原生构建;
- 已初始化 RUM;
- 当前存在有效 RUM View;
- 使用当前 SDK 版本组合中的 Cocos SDK 与原生依赖。
如果没有有效 RUM Context,SDK 会跳过当前帧,不会生成独立于 RUM 的重放数据。建议开启 autoTrack.scenes,或在截帧前手动调用 guanceSdk.rum.startView()。
安装独立 Replay 包¶
从 Cocos SDK 0.1.0-alpha.6 开始,会话重放由 @cloudcare/cocos-session-replay 单独提供。请在 Cocos 项目根目录安装完全相同版本的两个包:
npm install @cloudcare/cocos-sdk@0.1.0-alpha.7 @cloudcare/cocos-session-replay@0.1.0-alpha.7
npx --no-install guance-cocos install --project . --replay
重新打开 Creator,生成并编译原生工程。使用 CocoaPods 的 iOS 工程还需执行 pod install;SPM 配置和开关的保留规则见应用接入。
基础包不包含 Replay API、截帧实现或 Replay 原生依赖。以下示例将组合后的实例保存为 observability.ts 中导出的 guanceSdk,其他模块复用该实例。
初始化¶
说明
本页代码示例中的 ... 表示已省略 sdk 基础配置(例如 datakitUrl)。请先参照 SDK 初始化完成通用配置;本页仅展示 Session Replay 相关配置。
百分比采样字段的适用构建
本节与下文启停示例中的新采样字段适用于包含百分比采样改造的开发构建。上方安装命令中的 0.1.0-alpha.7 不包含该改造;使用该版本时,请将 sessionReplaySamplingRate: 100 改为 sampleRate: 1,将 sessionReplayOnErrorSamplingRate: 0 改为 sessionOnErrorSampleRate: 0。
import { guanceSdk as baseSdk } from '@cloudcare/cocos-sdk/creator3';
import { withSessionReplay } from '@cloudcare/cocos-session-replay/creator3';
export const guanceSdk = withSessionReplay(baseSdk);
guanceSdk.start({
...,
rum: {
androidAppId: 'android-rum-app-id',
iosAppId: 'ios-rum-app-id',
},
replay: {
sessionReplaySamplingRate: 100,
sessionReplayOnErrorSamplingRate: 0,
captureFps: 2,
maxImageDimension: 720,
imagePolicy: {
quality: 'medium',
},
touchPrivacy: 'show',
},
autoTrack: {
scenes: true,
},
});
Creator 2 请将两个包的导入入口都改为 /creator2。组合必须发生在 SDK 初始化或 Hybrid attach() 之前;后续的 .replay、start({ replay }) 与 attach({ replay }) 都在组合后的实例上调用。
| 字段 | 类型 | 必须 | 说明 |
|---|---|---|---|
sessionReplaySamplingRate |
number |
否 | Session Replay 会话采样百分比,范围 0–100,允许小数;未设置时沿用 Native Replay SDK 默认值 |
sessionReplayOnErrorSamplingRate |
number |
否 | 错误会话补采样百分比,范围 0–100,允许小数;默认 0 |
sampleRate |
number |
否 | 已废弃,建议使用 sessionReplaySamplingRate;保留原来的 0–1 单位和行为 |
sessionOnErrorSampleRate |
number |
否 | 已废弃,建议使用 sessionReplayOnErrorSamplingRate;保留原来的 0–1 单位和行为 |
captureFps |
number |
否 | 每秒截帧数,只允许整数 1–5,默认 1 |
maxImageDimension |
number |
否 | 截帧最长边像素,范围 1–2048;未指定时使用质量档位预设,默认 medium 为 720 |
imagePolicy |
FTReplayImagePolicy |
否 | 图片编码质量与单帧大小策略;显式传入后启用,适用构建见下文 |
touchPrivacy |
show / hide |
否 | 触摸数据隐私级别;show 记录触摸按下和抬起的位置,hide 不记录触摸位置,默认 hide |
非法采样率、FPS、图片尺寸或流量策略会在 TypeScript 层抛出 TypeError 或 RangeError。
新采样字段使用 0–100 的有限数值,0.1 表示 0.1%,100 表示全量。仅使用旧字段时仍按 0–1 校验,默认值与行为不变。同一采样项同时提供新旧字段时,新字段优先,包括显式的 0;新字段非法时会抛出 RangeError,不会回退到旧字段或截断数值。
iOS 小数百分比要求原生 Replay SDK 支持完整浮点采样链路;当前依赖的 iOS 1.6.8-alpha.5 使用整数采样属性,Bridge 会明确拒绝小数配置。Android 百分比字段由 Bridge 除以 100 后传给原生比例接口,具体限制见RUM 采样说明。
图片大小策略¶
适用构建
以下单帧限制从 0.1.0-alpha.7 开始提供。已发布的 0.1.0-alpha.6 不包含此调整;下文真机测量使用的是包含该调整的本地开发包,不能仅凭其 alpha.6 版本号判断功能。升级步骤见升级到 alpha.7。
captureFps 独立控制目标截帧频率,imagePolicy 控制图片编码质量和单帧大小。需要使用单帧限制时,应显式传入 imagePolicy:
replay: {
captureFps: 3,
maxImageDimension: 720,
imagePolicy: {
quality: 'medium',
maxFrameBytes: 40 * 1024,
},
}
| 档位 | 默认最长边 | 初始编码质量 | 每张图片上限 |
|---|---|---|---|
low |
480 px | 0.35 | 20 KiB |
medium |
720 px | 0.45 | 40 KiB |
high |
960 px | 0.60 | 80 KiB |
imagePolicy 支持以下字段:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
quality |
low / medium / high |
medium |
质量预设;不改变 captureFps |
maxFrameBytes |
number |
当前档位预设 | 每张图片编码后的最大字节数,范围 1 KiB–1 MiB,必须是整数;新 View 和方向变化的首帧也受此限制 |
显式设置的 maxImageDimension 和 imagePolicy.maxFrameBytes 会覆盖档位预设。Android V2 使用 WebP,iOS V2 使用 JPEG;编码超限时先降低质量,再缩小尺寸,仍超限则不保存该图片,待写入的触摸记录仍可继续保存。
0.1.0-alpha.7 移除图片滚动 60 秒预算、预算触发的降频和 100 KiB 首帧突发额度。升级时删除 imagePolicy.maxBytesPerMinute、imagePolicy.adaptiveCapture;这两个字段已不属于配置 API。captureFps 是目标频率,画面去重、截帧和编码耗时仍会影响实际输出;SDK 每次只处理一帧,超过采集时隙时跳过错过的时隙,不积压并发任务。
未传入 imagePolicy 时保留旧图片路径,没有编码字节数上限,不能套用上述单帧上限。传入 imagePolicy: {} 即采用 medium 预设。显式启用后需要原生 V2 图片接口;接口不可用或返回图片超限时会报告错误,不会退回无法保证大小限制的旧接口。
Camera 选择¶
默认使用当前场景中找到的第一个 Camera。多 Camera 项目应显式指定需要重放的 Camera:
import { guanceSdk } from './observability';
export function selectReplayCamera(camera: unknown): void {
guanceSdk.setReplayCamera(camera);
}
setReplayCamera() 每次只保存一个 Camera。多次调用时,后一次传入的 Camera 会覆盖此前设置,SDK 不会同时采集或合成多个 Camera。如果调用时上一帧正在采集,新 Camera 将从下一次采集开始生效。
切换主 Camera 后应再次调用 setReplayCamera()。如果场景中没有可用 Camera,当前帧会被跳过。
0.1.0-alpha.7中,Creator 3 使用独立离屏 Camera 截帧,避免修改显示 Camera 的渲染目标或影响依赖 Camera 的输入坐标。该调整不改变单 Camera 采集限制;升级后仍需验证多 Camera、屏幕方向变化以及节点遮罩的显示效果。
触摸隐私¶
touchPrivacy 控制 Session Replay 是否记录触摸位置:
| 模式 | 行为 |
|---|---|
show |
在 Replay 中记录触摸按下和抬起的位置 |
hide |
不记录触摸位置,默认值 |
触摸采集属于 Session Replay,与 autoTrack.actions 相互独立:即使没有开启 autoTrack.actions,touchPrivacy: 'show' 仍会记录 Replay 触摸;反之,开启 Action 自动采集但保留 touchPrivacy: 'hide' 时,Replay 中仍不会出现触摸位置。即使前后两帧画面没有变化,待写入的触摸操作也会单独保存到 Replay。
0.1.0-alpha.7修复 Creator 3 中被 UI 控件消费的触摸在 Replay 中遗漏的问题,并保留正常输入分发。开启 touchPrivacy: 'show' 后,应同时验证按钮、摇杆等控件的业务响应和 Replay 触摸位置,确认操作没有重复记录。该修复不扩大 autoTrack.actions 的采集范围。
当前 Cocos API 只支持全局触摸隐私设置,不支持按节点覆盖触摸隐私。guanceSdk.replay.setPrivacy(node, 'hide') 只隐藏节点画面,不会隐藏该位置上的触摸记录;敏感页面应在启动 Session Replay 时使用 touchPrivacy: 'hide'。
触摸位置隐私
触摸坐标可能暴露用户在敏感页面上的操作位置。只有在完成隐私评估并取得必要授权后才应设置为 show;否则保留默认值 hide。
节点隐私¶
所有 EditBox 节点默认使用 mask。还可以为指定节点设置规则:
guanceSdk.replay.setPrivacy(accountNode, 'mask');
guanceSdk.replay.setPrivacy(secretPanelNode, 'hide');
guanceSdk.replay.setPrivacy(publicNode, 'unmask');
| 模式 | 行为 |
|---|---|
mask |
以遮罩色覆盖节点矩形区域 |
hide |
以纯色隐藏节点矩形区域 |
unmask |
删除该节点的自定义规则 |
unmask 只删除自定义规则。节点如果仍是 EditBox,默认遮罩继续生效。
隐私区域按节点的世界坐标矩形计算。自定义渲染、粒子、Shader、RenderTexture 或超出节点包围盒的视觉内容不会自动推导隐私区域,必须在接入测试中逐场景检查。
按页面管理遮罩¶
setPrivacy() 的规则绑定到传入的节点实例,不按页面名称或 RUM View 自动切换。不同页面需要遮罩不同内容时,应由业务页面的进入、离开逻辑管理各自节点的规则。
下面以同一场景内切换“诊断页”和“操作页”为例:diagnosticsPage、motionPage 是两个页面的根节点,privateTokenNode 是诊断页内需要遮罩的普通节点。SDK 初始化或 Hybrid attach() 完成后,在页面切换时调用对应函数:
function showDiagnostics() {
// 每次进入都重新设置,确保敏感节点显示前已有遮罩规则。
guanceSdk.replay.setPrivacy(privateTokenNode, 'mask');
motionPage.active = false;
diagnosticsPage.active = true;
}
function showMotion() {
// 先隐藏敏感页面,再清除该页面节点的自定义规则。
diagnosticsPage.active = false;
guanceSdk.replay.setPrivacy(privateTokenNode, 'unmask');
motionPage.active = true;
}
操作页如果也有敏感节点,应在显示前为这些节点分别设置 mask 或 hide,离开时清除对应规则。一个页面包含多个自定义遮罩节点时,需要逐个管理。
页面生命周期中还需注意:
- 仅将页面或父节点设为
active = false,不会删除已注册的自定义规则;隐藏页面不能代替调用unmask,否则旧页面的遮罩区域可能影响后续画面。 - 页面离开或节点销毁前,清除该页面注册的自定义规则;可以将逻辑放在项目的页面管理器,或组件的启用、禁用和销毁回调中。
- 再次进入页面时重新设置规则;如果页面被销毁后重建,必须传入新创建的节点实例。
- 切换 RUM View 名称不会自动设置或清除节点规则;Hybrid
enterCocos()/leaveCocos()管理采集归属,页面仍需自行管理节点遮罩。 unmask只删除指定节点的自定义规则,不会关闭全局隐私保护,也不会取消EditBox默认遮罩。
这些规则影响 Cocos 截帧中的节点画面。Hybrid 原生页面仍使用宿主 Native SDK 的 Session Replay 隐私配置,触摸位置则由 touchPrivacy 单独控制。
验证时应覆盖“进入页面 → 切换到其他页面 → 再次进入”,在 Replay 中确认敏感内容持续被遮罩,其他页面没有残留遮罩。
更多隐私建议见数据与隐私。
运行行为¶
- 使用 Cocos
RenderTexture截取 RGBA 画面。 - 未配置
imagePolicy时保留旧图片路径;显式配置后,Android 使用 WebP V2,iOS 使用 JPEG V2,并检查实际编码大小。 - 隐私遮罩在图片压缩前完成。
- 内容完全相同或近似静止的帧会被跳过;View、画面尺寸或隐私规则变化会强制生成变化帧。
- 图片因去重或编码大小被跳过时,待写入的触摸记录仍会单独保存。
- 上一帧仍在处理时,不会并发处理新帧。
- 单帧捕获或编码失败只丢弃当前帧,不会停止后续 Session Replay 采集。
- 临时图像写入 Native SDK 后会从应用临时目录删除。
流量计算¶
下面仅计算单个已录制会话的图片载荷,1 KiB = 1024 bytes,1 MiB = 1048576 bytes。Replay Segment、触摸元数据、上传协议开销和重试需要单独计入。
计算方式¶
实测图片流量(MiB/分钟) = 去重后图片总字节数 ÷ 对应记录时长(秒) × 60 ÷ 1048576
规划图片流量(MiB/分钟) ≈ 平均编码字节数 × 每分钟预计保存图片数 ÷ 1048576
满帧图片理论上限(MiB/分钟) ≈ maxFrameBytes × captureFps × 60 ÷ 1048576
重复播放产生的下载按图片资源 ID 去重;复用同一图片的多条记录不重复累加资源大小。统计时长与图片集合必须对应,不能将整个 Replay 的图片总量除以其中一个 View 的时长。通过云端下载得到的是图片载荷大小,手机真实上传总流量还需在设备端测量。
六种配置的满帧理论上限¶
| 档位 | 单帧上限 | 2 FPS 图片理论上限 | 3 FPS 图片理论上限 |
|---|---|---|---|
low |
20 KiB | 2.34 MiB/分钟 | 3.52 MiB/分钟 |
medium |
40 KiB | 4.69 MiB/分钟 | 7.03 MiB/分钟 |
high |
80 KiB | 9.38 MiB/分钟 | 14.06 MiB/分钟 |
表中假设每帧都保存且达到单帧大小上限,是近似的满帧图片上限,不是典型消耗、总上传上限或滚动配额。例如 medium、3 FPS 的理论图片上限为 40960 × 3 × 60 ÷ 1048576 ≈ 7.03 MiB/分钟,实际图片通常小于 40 KiB。
六种配置的样本估算范围¶
下表使用 21 张既有 Battle 图片,经 libwebp 1.6.0 按 Android 策略重新编码,以最小和最大图片大小分别乘以每分钟 120 或 180 张估算。数值下限表示这批动态样本的参考下限,不是所有场景的最低流量。
| 档位 | 重编码样本大小 | 2 FPS 图片估算 | 3 FPS 图片估算 |
|---|---|---|---|
low |
5,482–6,054 bytes/张 | 0.63–0.69 MiB/分钟 | 0.94–1.04 MiB/分钟 |
medium |
10,168–11,282 bytes/张 | 1.16–1.29 MiB/分钟 | 1.75–1.94 MiB/分钟 |
high |
10,776–12,100 bytes/张 | 1.23–1.38 MiB/分钟 | 1.85–2.08 MiB/分钟 |
这些是已压缩图片的二次编码估算,尚未对六种配置分别进行连续真机录制。low 缩放至 480×270;medium/high 使用 720×405 源图且未放大,因此 high 数据不代表 960 px 截帧的流量。该表不适用于推断 iOS JPEG 流量,也不是其他场景的保证范围。
Android 真机参考¶
2026 年 9 月 13 日,Guance Cocos 开发包的 Creator 2.4.9 Android 示例的 Battle 场景使用 captureFps: 3、quality: 'medium'、最长边 720 px、每帧 40 KiB 上限。该场景 83 张 WebP 图片均已取得:
| 指标 | 结果 |
|---|---|
| 图片尺寸 | 720×405 |
| 图片总量 / 首末图片跨度 | 1,008,030 bytes / 28.516 秒 |
| 单张大小 / 平均大小 | 11,280–13,098 bytes / 12,144.94 bytes |
| 实测图片流量 | 2.02 MiB/分钟 |
| 含开头一次 1.017 秒间隔的平均帧率 | 2.88 FPS |
| 后续稳定阶段帧率 | 2.95 FPS |
| 按样本最小/最大大小、满 3 FPS 折算 | 1.94–2.25 MiB/分钟 |
| 按平均大小、满 3 FPS 折算 | 2.08 MiB/分钟 |
该测量是 Guance 开发包的设备参考,不代表另行完成了 TrueWatch 真机流量测试。对于这个 Android Battle 场景,可用约 2.0–2.1 MiB/分钟作为图片容量规划参考。该真机结果略高于前表 medium 的二次编码估算,应优先使用真机数据;low/high 仍只有样本重编码估算,不能据此声称已真机验证。
整段回放原始记录跨度为 68.953 秒,控制台会话头部显示 48.15 秒;应按对应原始记录时长计算。Battle 之外有两张图片未能从服务端取得,因此整段下载总量不作为完整上传流量参考。图片缺失、协议开销和重试均不能通过上述图片估算推导。
会话采样与整体容量¶
画面完全相同或近似静止时,去重会减少图片数量;采集和编码耗时也可能降低实际帧率。生产容量应以目标设备、真实场景的平均图片大小与保存频率估算,并分别测量高动态画面、菜单和静态页面。
会话采样控制参与录制的会话数量,不改变单个已录制会话的图片限制。若会话被均匀采样、录制时长和场景分布相近,可粗略估算普通采样部分:
使用旧字段时,公式中的 sessionReplaySamplingRate / 100 对应原来的 sampleRate;例如新字段 20 与旧字段 0.2 均表示 20% 的会话参与普通录制。
还需结合 RUM 采样及实际参与录制的分钟数;错误会话补采样产生的录制、Segment 和网络开销另外计入。需要准确计费或网络容量数据时,以设备端上传统计为准。
升级到 alpha.7¶
在 Cocos 项目根目录同时升级基础包和 Replay 包,并更新原生集成:
npm install @cloudcare/cocos-sdk@0.1.0-alpha.7 @cloudcare/cocos-session-replay@0.1.0-alpha.7
npx --no-install guance-cocos install --project . --replay
- 已使用
alpha.6拆包 API 的项目继续复用withSessionReplay(baseSdk)返回的实例。 - 删除
imagePolicy.maxBytesPerMinute和imagePolicy.adaptiveCapture。使用captureFps控制频率,使用maxImageDimension和imagePolicy.maxFrameBytes控制每张图片大小。旧 JavaScript 配置中保留这些已移除字段不会启用分钟预算。 - 每张图片都受单帧上限约束,包括新 View 和屏幕方向变化的首帧;不再提供滚动预算降频和首帧独立突发额度。请重新评估实际流量,见流量计算。
- 重新打开 Creator,生成并编译原生工程;使用 CocoaPods 时重新执行
pod install。仅替换 JavaScript 不能更新原生图像处理逻辑。 - 验证 Creator 3 的显示画面、按钮与摇杆响应、Replay 触摸位置,并检查 View 切换、横竖屏变化及隐私遮罩。
从一体包迁移¶
从 0.1.0-alpha.5 或更早版本升级时:
- 将基础包升级到已发布的
0.1.0-alpha.6或后续版本,安装同版本 Replay 包,并重新执行安装器--replay。 - 在首次
start()/attach()前调用withSessionReplay(baseSdk),让业务代码复用组合后的实例。 - 将原先独立导出的
setReplayCamera(camera)改为guanceSdk.setReplayCamera(camera)。 - 将
FTSessionReplayConfig、FTHybridSessionReplayConfig、FTReplayImagePolicy等 Replay 类型的导入移到@cloudcare/cocos-session-replay/creator2或/creator3。包含 Replay 的整体配置分别使用FTCocosReplayConfig与FTCocosHybridReplayConfig。 - 重新生成并编译原生工程;仅替换 JavaScript 不会安装新的 Replay Bridge。
若不再使用 Replay,移除组合及 Replay 配置,运行安装器 --no-replay 后重新构建。该开关用于移除安装器管理的原生集成;运行时暂停截帧仍使用下文的 replay.stop(),Hybrid 场景使用 leaveCocos()。
启停¶
已安装并组合 Replay 包的前提下,未在 guanceSdk.start() 中传入 replay,也可以在 RUM 初始化并启动 View 后单独开启:
guanceSdk.replay.start({
sessionReplaySamplingRate: 100,
captureFps: 1,
maxImageDimension: 720,
touchPrivacy: 'show',
});
停止截帧:
guanceSdk.shutdown() 也会停止截帧。不要同时通过 guanceSdk.start({ replay: ... }) 和 guanceSdk.replay.start() 重复启动。
原生宿主 Hybrid 模式不使用上述启停接口。Session Replay 由原生宿主以原生 recorder 模式初始化,Cocos 在 enterCocos() 和 leaveCocos() 之间自动切换到外部捕获源,详见原生宿主 Hybrid 接入。
性能建议¶
- 从
captureFps: 1、imagePolicy: { quality: 'medium' }开始验证;需要更连贯画面时再提高到2 fps。 - 只在需要重放的业务环境开启采样。
- 低端设备出现 GPU、内存或磁盘压力时,优先改用
low,再降低最长边尺寸和采样率。 - 在横竖屏切换、多 Camera、复杂 UI、低帧率场景下验证图像方向与遮罩位置。