HarmonyOS 会话重放(实验性)¶
HarmonyOS Session Replay 通过记录 ArkUI 页面结构、视觉变化和用户操作重建页面,并关联 RUM Session、View 和 Error。ArkWeb 页面还需要集成 Browser SDK。该能力由独立的 ft_session_replay 包提供。
当前为 Alpha 预发布版本 0.1.0-alpha04,功能和 API 仍可能调整。
前置条件¶
- 确保已设置并初始化 SDK RUM 配置,并开启 View 的监控采集。
- HarmonyOS Session Replay 需要使用
ft_sdk0.1.18-alpha04及以上版本,并额外安装ft_session_replay。 - 自动采集需要接入支持 Session Replay 的
@cloudcare/hvigor-ohos-plugin,在完成 RUM 初始化后初始化 Replay。 - 应用需使用 HarmonyOS API 12 及以上,并开启规范化 OHMUrl。插件当前验证环境为 Node.js 18+、Hvigor 6.23.5 和 HarmonyOS SDK 6.0.2(API 22)。
- 使用本地部署时,需按移动端会话重放采集器配置开启回放接收;公网 DataWay 无需额外配置。
配置¶
引入 SDK¶
在需要自动采集的应用模块中安装核心包和 Replay 包:
使用本地 HAR 时,在模块的 oh-package.json5 中声明 ft_sdk.har、ft_session_replay.har 的 scoped 依赖,并在工程根目录通过 overrides 将 Replay 依赖的核心包指向同一个本地 HAR,配置方式与扩展包本地接入相同。
引入 Hvigor 插件¶
在工程级 hvigor/hvigor-config.json5 添加构建插件:
在应用 HAP 的 hvigorfile.ts 注册:
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { ftConsoleLogPlugin } from '@cloudcare/hvigor-ohos-plugin';
export default {
system: hapTasks,
plugins: [ftConsoleLogPlugin()]
};
每个需要自动采集的源码模块必须在自己的 oh-package.json5 的 dependencies 声明核心包和 Replay 包。只在根目录、其他模块或 devDependencies 声明不会启用该模块的插桩。插件自动处理支持的 @Entry 页面根节点、可见性、触摸、Router 转场以及 ArkUI Web 控件与 controller 的关联,并保留已有回调。
代码调用¶
在 UIAbility.onCreate 中,依次初始化核心 SDK、RUM 和 Replay。将应用私有的 filesDir 传入 Replay 以持久化缓存。
import { UIAbility } from '@kit.AbilityKit';
import {
FTSDK, FTSDKConfig, FTRUMConfig
} from '@guancecloud/ft_sdk/Index';
import {
FTSessionReplay, FTSessionReplayConfig,
TouchPrivacy, ImagePrivacy, TextAndInputPrivacy
} from '@guancecloud/ft_session_replay/Index';
export default class EntryAbility extends UIAbility {
onCreate(): void {
FTSDK.install(FTSDKConfig.builder('YOUR_DATAKIT_URL'), this.context);
FTSDK.installRUMConfig(new FTRUMConfig()
.setRumAppId('YOUR_RUM_APP_ID')
.setSessionSamplingRate(100)
.setEnableTraceUserView(true));
const replayConfig = new FTSessionReplayConfig()
.setSampleRate(10)
.setTouchPrivacy(TouchPrivacy.SHOW) // 显示触摸位置。
.setImagePrivacy(ImagePrivacy.MASK_LARGE_ONLY) // 屏蔽大图。
.setTextAndInputPrivacy(TextAndInputPrivacy.MASK_SENSITIVE_INPUTS) // 屏蔽密码等敏感输入。
.setDelayInit(true);
const replay = FTSessionReplay.getInstance();
replay.init(replayConfig, this.context.filesDir);
// 开始录制。
replay.start();
}
}
示例使用 setDelayInit(true),在 init() 后调用 start() 开始录制;不设置时,init() 默认自动启动。
接入 Hvigor 插件后会自动采集触摸事件和 Router 页面转场;自定义 Navigation 转场参见 ArkUI 支持。
需要停止录制时调用 replay.disable(),恢复时调用 replay.start()。停止后,已接受的帧继续保存,自动上传会继续处理待上传数据;不影响 RUM 采集,也不清除已有 Replay 缓存。
可调用 await replay.flush() 立即请求上传。数据存储在应用私有目录,Replay 包不额外加密这些文件。
| 方法名 | 类型 | 必须 | 含义 |
|---|---|---|---|
setSampleRate |
number |
否 | 设置 Session Replay 采样率,取值范围 [0,100],0 表示不采集,100 表示全采集,默认值为 100,支持小数 |
setSessionReplayOnErrorSampleRate |
number |
否 | 设置错误录制采样率,作用于未命中普通录制的 Session;本地保留错误前 1 分钟的数据,收到关联 RUM Error 后进入上传队列。取值范围 [0,100],默认值为 0,支持小数 |
setTextAndInputPrivacy |
TextAndInputPrivacy |
否 | 设置文本和输入屏蔽级别。MASK_SENSITIVE_INPUTS 保留普通文本、屏蔽敏感输入;MASK_ALL_INPUTS 屏蔽所有输入;MASK_ALL 屏蔽文本和输入,默认 MASK_ALL |
setCaptureVisiblePassword |
boolean |
否 | 是否允许采集用户主动显示的密码,默认 false;MASK_ALL_INPUTS、MASK_ALL 下仍屏蔽 |
setImagePrivacy |
ImagePrivacy |
否 | 设置图片屏蔽级别。MASK_ALL 屏蔽所有图片;MASK_LARGE_ONLY 屏蔽大图;MASK_NONE 不屏蔽图片,默认 MASK_ALL |
setTouchPrivacy |
TouchPrivacy |
否 | 设置触控屏蔽级别。SHOW 记录触摸位置,HIDE 隐藏触摸位置,默认 HIDE |
enableLinkRUMKeys |
Array<string> |
否 | 关联指定的 RUM 上下文字段至会话重放数据,默认空数组,可用于回放数据分流 |
setDelayInit |
boolean |
否 | 是否延迟启动录制,默认 false;设置为 true 后,需调用 start() 开始录制 |
Replay 采样与 RUM 采样独立配置,不受核心 SDK 远程采样配置覆盖。
RUM 关联¶
成功保存回放帧后,关联的原生 View、Action、Resource、LongTask、Error 可携带 session_has_replay=true;Session 聚合数据使用 has_replay 表示当前会话是否关联回放数据。回放标记由 SDK 根据实际录制结果自动设置,仅完成 Replay 初始化不代表已有可用回放数据。
隐私配置¶
SDK 支持通过 FTSessionReplayConfig 配置全局屏蔽级别,包括:
- 图片屏蔽级别
- 文本和输入屏蔽级别
- 触控屏蔽级别
注意:
- 以下配置应在
init()前设置,作用于会话重放的全局采集。 - RUM 的
DataModifier、LineDataModifier用于遥测字段脱敏;回放画面使用本节的隐私配置。
以下示例中的 replayConfig 和枚举沿用代码调用中的定义。
图片屏蔽¶
使用 setImagePrivacy(ImagePrivacy) 设置图片屏蔽级别。
文本和输入屏蔽¶
使用 setTextAndInputPrivacy(TextAndInputPrivacy) 设置文本和输入屏蔽级别。
// 保留普通文本,屏蔽密码等敏感输入。
replayConfig.setTextAndInputPrivacy(TextAndInputPrivacy.MASK_SENSITIVE_INPUTS);
允许采集主动显示的密码时,页面需将 showPassword 绑定到与 onSecurityStateChange 同步的状态;仅开启 setCaptureVisiblePassword(true) 不会覆盖文本隐私策略。
触控屏蔽¶
使用 setTouchPrivacy(TouchPrivacy) 设置是否屏蔽触摸位置。
Webview Session Replay¶
ArkWeb 需要同时满足以下条件:
- 原生 RUM 开启
setEnableTraceWebView(true),并按 WebView 数据监测接入FTWebViewHandler。 - 原生 Replay 已初始化并启动,并通过 Hvigor 插件关联 Web 组件与 controller。
- 网页集成支持原生 Replay Bridge 的 Browser SDK,并在网页中调用
startSessionReplayRecording()。
提示:建议先启动原生 Replay 并绑定
FTWebViewHandler,再加载网页 Browser SDK。网页回放受原生 Replay 采样控制,隐私级别默认由原生 Bridge 提供,也可通过网页的 defaultPrivacyLevel 设置。
ArkUI 支持¶
支持的采集内容包括页面结构、文本、布局、滚动、支持的动画和原生控件、覆盖层、图片及绘制组件。
图片支持范围¶
支持 Image 和 ImageAnimator 图片组件。普通 Image 图片通过系统组件快照采集,需图片已加载、组件可见且可读取画面;Base64 图片可直接读取编码数据。
| 图片来源 | 典型用法 | 支持说明 |
|---|---|---|
| 应用资源图片 | Image($r('app.media.icon')) |
自动采集组件显示的图片画面。 |
| 本地文件图片 | Image 加载应用可访问的本地路径或 file:// 地址 |
图片加载并显示后可自动采集。 |
| 网络图片 | Image 加载 HTTP(S) 图片地址 |
采集组件已加载的画面;加载失败或尚未显示时没有对应图片内容。 |
| 内存图片 | Image 使用 PixelMap |
自动采集组件显示的内存图片。 |
| 可绘制资源 | Image 使用 DrawableDescriptor |
资源成功渲染到图片组件后可自动采集。 |
| Base64 内嵌图片 | data:image/...;base64,... |
支持读取图片编码数据,格式和大小限制见下文。 |
无法自动获取的图片,可通过 registerImageAsset(...) 按图片组件 ID 或图片源字符串手动提供编码数据。
Base64 内嵌图片和手动补充资源支持 PNG(image/png)、JPEG(image/jpeg)、GIF(image/gif)、WebP(image/webp)和 SVG(image/svg+xml)。单份图片编码数据不能超过 2 MiB;Base64 图片按解码后的大小计算。
绘制组件支持¶
以下组件支持通过组件快照采集画面:
| 类别 | 支持组件 |
|---|---|
| 二维码 | QRCode |
| 画布 | Canvas |
| 图形绘制 | Shape、Rect、Circle、Ellipse、Line、Polygon、Polyline、Path |
采集限制¶
| 适用范围 | 限制说明 |
|---|---|
| 图片及绘制组件 | 图片屏蔽配置默认使用 ImagePrivacy.MASK_ALL,会屏蔽画面内容。绘制组件在 TextAndInputPrivacy.MASK_ALL 下也会屏蔽画面内容。 |
| 组件快照 | API 12~14 需为图片或绘制组件设置稳定的 .id(...)。采集画面可能经过缩放,不保证保留原始分辨率。 |
| 动画图片 | ImageAnimator 以采样画面记录动画变化,不保证逐帧还原;普通 Image 中的动图也不保证与原动画完全同步。 |
| 原生动画与视觉效果 | 原生动画、模糊材质、文本布局和系统默认转场的播放效果可能与原画面存在差异。 |
| 富文本 | RichText 只采集文本、段落和基本样式,不采集其中的脚本、HTML 图片或复杂 Web 布局。 |
| PatternLock | 可能需要额外转发或显式提供内容,不能仅靠安装插件保证完整录制。 |
| Navigation 转场 | 要求 API 15+。自定义转场需额外转发,可使用 updateNavigationTransition(...) 和 finishNavigationTransition(...) 转发进度与结束状态。 |
高级配置¶
手动页面接入¶
import { FTSessionReplay } from '@guancecloud/ft_session_replay/Index';
@Entry
@Component
struct ReplayPage {
private replay: FTSessionReplay = FTSessionReplay.getInstance();
private registerReplayRoot(): void {
this.replay.registerRoot(this.getUIContext(), 'replay-page-root', vp2px(1));
}
onPageShow(): void {
this.registerReplayRoot();
}
onPageHide(): void {
this.replay.unregisterRoot();
}
build() {
Column() {
Text('Session Replay');
}
.id('replay-page-root')
.onAreaChange(() => this.registerReplayRoot())
.onTouch((event: TouchEvent) => this.replay.recordTouchEvent(event))
}
}
注意:未由插件自动注册根节点的 ArkUI 页面,可按上述示例手动接入。若页面显示后才启动 Replay,需重新调用
registerRoot(...)注册当前页面。子组件拦截触摸事件时,需通过recordTouchEvent(event)转发;如需显示触摸位置,请开启TouchPrivacy.SHOW。