Session Replay 是火山引擎提供的会话回放解决方案,当前已支持 Android 端 SDK 接入,帮助用户快速实现会话回放。本文为您介绍Android端的Session Replay SDK接入指导
注意
会话回放 Android 端 SDK 目前处于 Beta 验证阶段,接入前可以先联系火山技术人员 ,我们第一时间提供帮助和指引。
Session Replay SDK 依赖 Finder SDK 进行数据回流,在使用弹窗 SDK 前,请确保已经集成了 Finder SDK,接入操作请参见:Finder Android SDK接入指南。
注意
1、Session Replay SDK仅依赖Finder SDK进行内置埋点上报+注入回放ID参数,不会通过Finder SDK间接获取任何个人信息参数。
2、若您希望了解您接入的Finder SDK控制个人信息方式,请参考该sdk的合规使用说明
引入火山maven仓库地址。
Gradle 7.0 以下
// 在 project 级别的 build.gradle 中添加 maven 仓库 // 在 allprojects 的 repositories 中添加 maven 仓库 allprojects { repositories { maven { url 'https://artifact.bytedance.com/repository/Volcengine/' } // 其他仓库 } }
Gradle 7.0 及以上
// 在 project 级别的 setting.gradle 中添加 maven 仓库 dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { // 省略其他 maven{ url 'https://artifact.bytedance.com/repository/Volcengine/' } } }
添加SDK依赖。
//在app:build.gradle下添加 dependencies { // 最新版本请联系火山技术人员获取 implementation 'com.bytedance.tea:tea_replay:x.x.x' }
在开始集成前,首先需要在集团中拥有一个应用,进行 SDK 集成前,您需要获取对应应用的 appkey 信息。
首先您需要初始化 Finder SDK,具体可参考:2.3 初始化 SDK,再初始化会话回放 SDK。
注意
import com.bytedance.applog.AppLog; import com.bytedance.session_replay_sdk.config.InitConfig; private static final String APP_KEY = "xxxxx";//替换成你自己的appkey //初始化配置 InitConfig config = new InitConfig.Builder() .setAppKey(APP_KEY)//设置appkey .setAutoStart(true)//是否自动启动录制,目前仅支持自动,默认传true即可 .setEnvironmentType(EnvironmentType.SAAS_BYTE_CLOUD)//设置环境类型,SAAS_BYTE_CLOUD(SaaS-非云原生),SAAS_VOLC_CLOUD(SaaS-云原生) .setUBAConfig((s, jsonObject) -> { AppLog.onEventV3(eventName, eventParams) })//设置UBA上报回调,目前仅支持Finder .setBlockSizeLimit(1024)//设置单个录制文件大小限制,单位kb,默认1024kb .setRecordMode(RecordMode.BLOCK)//设置录制模式,默认block模式 .build(); //初始化api调用 SessionReplaySDK.INSTANCE.init(application, mInitConfig);
参数 | 类型 | 是否必传 | 默认值 | 描述 |
---|---|---|---|---|
appKey | String | 是 | 空字符串 | appkey 从平台获取 |
environmentType | 枚举(EnvironmentType) | 是 | PROD_INTERNAL | 设置环境类型, |
autoStart | Boolean | 是 | true | 是否自动启动录制,目前仅支持自动,默认传true即可 |
ubaConfig | IUBAConfig | 是 | null | UBA上报回调,目前仅支持Finder,参考 3.2 代码示例 |
blockSizeLimit | Int | 否 | 1024 | 分片大小,单个录制文件的大小,单位kb |
remoteImageTagKey | Int | 否 | SDK内置资源ID | 用于设置网络图片的tag,具体用法参考第6节 |
replayQuality | 枚举(ReplayQuality) | 否 | 中等画质 | 画质,仅限制截图的分辨率:
|
enableLog | Boolean | 否 | false | 日志开关 |
customLogger | ILoggerConfig | 否 | null | 使用自定义方式输出日志,具体用法参考第 10 节 |
loggerLevel | Int | 否 | 全部等级 | 输入日志的等级,设置后仅会输出等级小于等于此等级的日志,默认全部等级。 |
localDebug | Boolean | 否 | false | (仅调试用)本地调试开关,开启后仅录制在本地,不上传服务器(通常用于本地联调录制数据不想上传服务器) |
recordMode | 枚举(RecordMode) | 否 | BLOCK | 录制模式:具体用法参考第三章节
|
expireDuration | Long | 否 | 604,800,000 | 本地保存的时间(单位为ms),仅当recordMode为LOCAL时有效,默认值保存7天 |
isReplayEnabled | Boolean | 否 | true | 是否启用会话回放 |
textFullyDesensitize | Boolean | 否 | false | 文本全脱敏(开启后,所有的文本都将转化为*上报)。 |
说明
SDK在特定时机会触发回调,您可以通过设置回调监听来获取回放相关的信息。
void setReplayCallBack() { SessionReplaySDK.INSTANCE.setReplayEventCallBack(new IReplayEventCallBack() { @Override public boolean rootViewShouldPush(@NonNull View view) { // 参数view是activity / dialog / toast 对应window的根节点 // 返回true,表示该view 需要被录制 //返回false, 表示该view不应该被录制 return true; } @Override public void onRecordingRootViewPush(@NonNull String recordingId) { //开始录制时调用,这里需要给录制id赋值,后续在第5条(埋点中注入录制ID参数)中会用到 mRecordingId = recordingId; } @Override public void onRecordingPause(@NonNull String recordingId) { //停止录制时调用,一般是跳出白名单的页面,这里需要将获取到的录制id置空 mRecordingId = null; } @Override public void onRecordingInit(@NonNull String recordingId) { //初始化成功之后回调 } @Override public void onRecordingCreated(@NonNull String recordingId) { //录制内容上传成功时回调 } }); }
说明
使用此方法,将录制ID注入到埋点中,以便后续回放时,可以将画面帧和埋点内容对应上,如果不注入,则回放内容无法对应Finder埋点。
import com.bytedance.applog.AppLog import com.bytedance.applog.UriConfig import com.bytedance.applog.event.AutoTrackEventType import com.bytedance.applog.event.EventBasicData import com.bytedance.applog.event.EventPolicy import com.bytedance.applog.event.EventType void setEventHandler() { AppLog.setEventHandler(new com.bytedance.applog.event.IEventHandler() { @Override public int acceptType() { return EventType.EVENT_ALL; } @Override public EventPolicy onReceive(int eventType, String eventName, JSONObject properties, EventBasicData basisData) { try { if (!TextUtils.isEmpty(mRecordingId)) { properties.put("\$sr_recording_id", mRecordingId); } } catch (JSONException ignored) { // 忽略异常 } return EventPolicy.ACCEPT; } }); }
注意
为了提升网图采集的性能,强烈建议业务方主动绑定网图的url到ImageView的指定tag上,这样回放端可以直接使用url加载图片,而无需SDK进行截图,解码,上传。
//如果您的应用统一封装了网图加载的方法或基类,可以在网图统一加载的地方进行设置 void setImageUrl(ImageView imageView,String url) { // 将 url 设置到 imageView 的对应 tag 上 imageView.setTag(SessionReplaySDK.INSTANCE.getRemoteImageTagKey(), url); }
说明
需要指定某些页面可以使用录制功能,可以通过设置白名单页面来实现。因目前会话回放还是beta版本,建议设置白名单页面,控制录制范围,避免复杂页面出现适配问题。
private void setActivityWhiteList() { SessionReplaySDK.INSTANCE.setActivityWhiteList(new HashSet<String>() {{ //A页面,完整包名+类名 add("com.xxx.AActivity"); //B页面完整包名+类名 add("com.xxx.BActivity"); }}); }
说明
应用中如果有自定义组件,自己写了绘制逻辑,需要调用以下方法,将自定义组件注册到录制SDK中,SDK会根据配置进行截图采集。
private void setCustomViewMap() { HashMap<String, CustomViewModel> map = new HashMap<String, CustomViewModel>() {{ // 内部绘制逻辑比较耗时,可以设置延迟截取 put("com.lynx.xx.LynxView", new CustomViewModel(CustomViewType.ASYNC_VIEW, 60L)); put("com.xxx.xxx.CustomView", new CustomViewModel(CustomViewType.ASYNC_VIEW, 60L)); // 普通组件,无需延迟 put("com.ss.android.tui.component.selector.TUISwitchButton", new CustomViewModel()); }}; SessionReplaySDK.INSTANCE.registerCustomViewMap(map); }
说明
如果需要录制保存在本地,用户主动授权后再上传服务器,可以使用此功能。
SessionReplaySDK.INSTANCE.openSingleTimeAuthPanel( new AuthConfig.Builder() .title("反馈授权提示") // 弹窗标题 文本自己定义 .content("授权上报您近 1 小时内的操作记录,助您更快解决问题。")//弹窗提示内容 文本自己定义 .positiveButtonText("上报")//弹窗确认按钮文本 文本自己定义 .negativeButtonText("取消") //弹窗取消按钮文本 文本自己定义 .build() );
说明
某些项目可能会屏蔽android 的Log.d 和 Log.e 等方法,需要使用自定义的日志输出方法,请参考如下代码。
initConfig.setCustomLogger(new ILoggerConfig() { @Override public void v(@NonNull String tag, @NonNull String message, @Nullable Throwable throwable) { // 自定义v日志输出 Log.v(tag, message); } @Override public void d(@NonNull String tag, @NonNull String message, @Nullable Throwable throwable) { // 自定义d日志输出 Log.d(tag, message); } @Override public void i(@NonNull String tag, @NonNull String message, @Nullable Throwable throwable) { // 自定义i日志输出 Log.i(tag, message); } @Override public void w(@NonNull String tag, @NonNull String message, @Nullable Throwable throwable) { // 自定义w日志输出 Log.w(tag, message); } @Override public void e(@NonNull String tag, @NonNull String message, @Nullable Throwable throwable) { // 自定义e日志输出 Log.e(tag, message); } })
说明
使用此模式,录制时,会将录制内容分片存储,当一个分片容量达到上限后,会创建新的分片并上传老的分片内容。本质上是一种边录边传的模式。
使用参考
InitConfig initConfig = new InitConfig.Builder(); initConfig.setRecordMode(RecordMode.BLOCK);//设置为BLOCK模式
说明
使用此模式,录制时,会将录制内容分片存储,当一个分片容量达到上限后,会创建新的分片,但不会上传。后续可以按需上传。
使用参考
//初始化 InitConfig initConfig = new InitConfig.Builder(); initConfig.setRecordMode(RecordMode.LOCAL);//设置为LOCAL模式 initConfig.setExpireDuration(1000 * 60 * 60)// 设置1小时过期(建议设置, 默认值是7天)
如何上传
手动调用flush上传
SessionReplaySDK.INSTANCE.flush(context);
弹出授权弹窗,用户授权同意后上传
SessionReplaySDK.INSTANCE.openSingleTimeAuthPanel( new AuthConfig.Builder() .title("反馈授权提示") // 弹窗标题 文本自己定义 .content("授权上报您近 1 小时内的操作记录,助您更快解决问题。")//弹窗提示内容 文本自己定义 .positiveButtonText("上报")//弹窗确认按钮文本 文本自己定义 .negativeButtonText("取消") //弹窗取消按钮文本 文本自己定义 .build() );