跳转至

原生与 Cocos 混合开发

本文介绍原生与 Cocos 混合开发场景下的 SDK 接入方式,适用于以 Android/iOS 原生页面为主、部分页面使用 Cocos Creator 的应用。原生宿主负责初始化观测 SDK,Cocos 只在自身页面可见期间接管 Cocos 层的 RUM View、自动采集和 Session Replay 画面捕获。

当前自动管理范围仅支持独立的 Cocos Activity 或 UIViewController。嵌入原生页面局部区域的 Cocos Surface 需要宿主手动管理 RUM View,不支持自动替换并恢复宿主页面 View。

接入边界

独立 Cocos 应用与原生和 Cocos 混合开发的应用使用不同的初始化入口:

场景 初始化入口 配置所有者 结束方式
应用整体由 Cocos 驱动 guanceSdk.start() Cocos guanceSdk.shutdown()
原生 App 局部使用 Cocos 原生 SDK 初始化后调用 guanceSdk.attach() 原生宿主 Cocos 页面调用 guanceSdk.leaveCocos()

start() 与 attach() 互斥。进入 Hybrid 模式后,SDK 会拒绝 Cocos 侧的 mobile.start()、rum.start()、logger.start()、trace.start()、replay.start()、replay.stop() 和 shutdown() 调用,避免重复初始化或关闭原生宿主持有的 SDK。用户绑定、RUM 事件、日志写入和 Trace Header 等非初始化 API 仍可通过 bridge 使用。

本页 Replay 示例使用 withSessionReplay(baseSdk) 返回的 guanceSdk。请先按应用接入安装两个同版本 npm 包并运行 --replay;具体导入见下文接入 Cocos 生命周期。只采集 Cocos RUM、Log、Trace 时,可直接使用基础包的 attach({ autoTrack }),无需安装 Replay。

attach() 只接受 Cocos 捕获和自动采集配置:

guanceSdk.attach({
  replay: {
    captureFps: 1,
    maxImageDimension: 720,
    touchPrivacy: 'show',
  },
  autoTrack: {
    scenes: true,
    actions: true,
    errors: true,
    network: true,
  },
});

attach() 会通过 FTCocosBridge 确认原生宿主已经初始化 SDK,并向原生全局上下文追加 sdk_package_cocos 版本信息;它不会传递上报地址、RUM App ID、采样率或重新初始化任何原生模块。

Replay 与 RUM 的采样决策、会话、数据存储和全局配置继续由原生 SDK 管理。

独立运行模式的 sessionSamplingRate、logSamplingRate、traceSamplingRate 及 Replay 百分比采样字段不属于 attach() 配置。Hybrid 模式仍在原生宿主初始化时设置采样,单位、字段名和小数支持以宿主所用的 Android/iOS Native SDK 为准;不要把 Cocos 的采样参数传给 attach() 或 enterCocos()。

touchPrivacy 只控制 Cocos 页面 Replay 是否记录触摸位置;原生页面继续使用宿主的 Session Replay 隐私配置。可选值、默认行为和隐私注意事项见 Cocos Creator 会话重放。

原生宿主需按SDK 版本与依赖要求配置与所安装 npm 包配套的原生 SDK。配套的 Android/iOS SDK 支持 Hybrid Replay,可在 Cocos 页面进入和离开时切换原生与 Cocos 画面捕获。

初始化原生宿主

Cocos npm/ZIP 安装包已经包含 TypeScript API、Creator 扩展以及 Android/iOS 的 FTCocosBridge,无需在宿主工程中额外添加初始化辅助类。可选 Replay 包提供 FTCocosReplayBridge 和图像处理代码,两个 Bridge 共享宿主使用的同一版本原生 SDK。

Android/iOS App 按各自原生 SDK 的接入要求初始化所需的 RUM、Logger、Trace 和 Session Replay,并确保在首次调用 guanceSdk.attach() 前完成初始化。具体配置参考:

iOS 宿主可按 SPM 接入说明切换依赖管理方式。宿主与 Cocos Bridge 应使用同一份原生 SDK,避免同时通过 CocoaPods 和 SPM 引入。仓库中的 Hybrid 示例读取同一份 cocos-sdk.config.json;更新本地扩展并重新生成 iOS 工程后,继续执行示例原有的 native:install 命令,安装器会通过 SPM 关联 Bridge 和 HybridSampleHost。宿主初始化及 Cocos attach() 流程保持不变。

对于独立的 Cocos Activity 或 UIViewController,无需为 Hybrid 接入改写原生 SDK 的初始化流程。Cocos 页面显示和离开时,分别调用 enterCocos() 与 leaveCocos() 完成 RUM View 和 Replay 捕获源的切换。

如果启用 Session Replay,原生宿主必须使用默认的原生 recorder 模式完成初始化,不要设置为 external-only;Cocos 侧仅在 attach() 中传入画面捕获配置。

Android 网络采集建议

HttpURLConnection 自动采集从 Android Agent 1.7.6-alpha03 搭配 Android Gradle Plugin 1.3.9-alpha01 开始支持,两个组件均需使用该版本或更高版本。

推荐开启 Cocos autoTrack.network: true,保持原生 HttpURLConnection 自动采集关闭(默认关闭)。原生宿主在初始化 RUM 前配置:

rumConfig.setEnableTraceUserResource(true);
rumConfig.setEnableHttpURLConnectionResource(false);

这样由 Cocos JS 层采集网络请求,同时保留原生 Resource 总开关,供宿主的 OkHttp 等请求使用。

冲突原因:Android 上的 Cocos JS XHR 底层会经过引擎的 HttpURLConnection 封装,Creator 2 对应 Cocos2dxHttpURLConnection,Creator 3 对应 CocosHttpURLConnection。同时开启 JS 和原生 HttpURLConnection 采集,会对同一次请求分别上报 Resource;两层没有跨层去重,同时注入 Trace Header 还可能导致 Resource 的 Trace 信息与服务端收到的请求头不一致。

iOS 网络采集建议

iOS SDK 1.6.8-alpha.5 新增 NSURLConnection 自动 Resource 采集与 Trace 关联,分别通过 FTRumConfig.enableTraceURLConnectionResource 和 FTTraceConfig.enableAutoTraceURLConnection 开启,默认均为 NO。这两个开关独立于用于 NSURLSession 的 enableTraceUserResource 和 enableAutoTrace;仅升级版本或打开原有开关不会启用 NSURLConnection 采集。

先确认当前引擎的实际请求实现,再选择采集层:

iOS 请求路径 原生 Resource 开关 原生 Trace 开关
Creator 2.4.9 / 2.4.15 XHR:NSURLConnection enableTraceURLConnectionResource enableAutoTraceURLConnection
Creator 3.8.8 XHR:NSURLSession enableTraceUserResource enableAutoTrace

同一次 Cocos XHR 同时被 autoTrack.network 和对应的原生 Resource 采集覆盖时,JS 与原生层会分别上报 Resource,当前没有跨层去重。Trace Header 相同也不代表 Resource 已去重。NSURLConnection 采集会复用能识别的已有 Trace Header,不应直接套用 Android 双开后覆盖 Trace Header 的结论。

对于 Creator 2,推荐保留 Cocos autoTrack.network: true,保持原生专用开关关闭,并保留宿主独立的 NSURLSession 采集:

rumConfig.enableTraceUserResource = YES;
rumConfig.enableTraceURLConnectionResource = NO;
traceConfig.enableAutoTrace = YES;
traceConfig.enableAutoTraceURLConnection = NO;

如果由原生层采集 NSURLConnection,在原生 RUM / Trace 初始化前将上述两个专用开关设为 YES,同时关闭 Cocos autoTrack.network。如果仍需 JS 采集其他请求,可通过原生 resourceUrlHandler 按 URL 排除重叠请求(返回 YES 表示不采集 Resource),并单独确认 Trace 注入策略;Resource 过滤不会关闭 Trace 注入。

Creator 3.8.8 / iOS 的实际 XHR 对照中,JS 与原生双开时,3 次 HTTP 请求产生 6 条 Resource;只开任一层时均为 3 条。双开时两条记录的 Trace ID / Span ID 不同,服务端收到的是原生层注入的请求头。

对于 Creator 3.8.8,关闭 NSURLConnection 专用开关不能避免 NSURLSession 路径的重复。宿主已开启 NSURLSession 自动采集时,可将 Cocos autoTrack.network 设为 false,由原生层统一采集;如保留 JS 采集,则需避免原生 Resource 采集覆盖相同请求,同时保留宿主其他网络请求的采集需求。

业务手动调用 startResource / stopResource / addResource 时,也需要避开原生自动采集的同一请求。保存并调用未经 JS SDK 包装的 XHR 方法只能绕过 JS 自动采集,不能绕过原生采集。

验证时给每次请求添加唯一 request_id,将实际 HTTP 请求数与上传的 Resource 数逐一对应,并检查 HTTP 状态、耗时及 Trace ID / Span ID。页面显示请求成功不足以证明 Resource 自动采集成功。

接入 Cocos 生命周期

以下示例使用 Creator 3;Creator 2 需将基础包和 Replay 包的导入入口都改为 /creator2。

import { guanceSdk as baseSdk } from '@cloudcare/cocos-sdk/creator3';
import { withSessionReplay } from '@cloudcare/cocos-session-replay/creator3';

export const guanceSdk = withSessionReplay(baseSdk);

export function attachObservability(camera?: unknown): void {
  if (camera) guanceSdk.setReplayCamera(camera);
  guanceSdk.attach({
    replay: {
      captureFps: 1,
      maxImageDimension: 720,
      touchPrivacy: 'show',
    },
    autoTrack: {
      scenes: true,
      actions: true,
      errors: true,
      network: true,
    },
  });
}

export function enterCocos(viewName = 'Cocos'): void {
  guanceSdk.enterCocos({ viewName });
}

export function leaveCocos(): void {
  guanceSdk.leaveCocos();
}

在 Cocos 页面组件中绑定生命周期:

onLoad(): void {
  attachObservability();
}

onEnable(): void {
  enterCocos('Game');
}

onDisable(): void {
  leaveCocos();
}

onDestroy(): void {
  leaveCocos();
}

默认使用当前场景中找到的第一个 Camera。多 Camera 项目应把用于重放的 Camera 传给 attachObservability(camera),切换主 Camera 后再次调用 guanceSdk.setReplayCamera(camera)。

attach()、已经进入后的 enterCocos(),以及已经离开后的 leaveCocos() 都是幂等操作。销毁路径可以再次调用 leaveCocos(),用于覆盖异常退出或重复回调。

如果 recorder 切换失败,相关调用会抛出错误。排除 Native SDK 版本或初始化问题后,应再次调用当前生命周期方法完成进入或离开,不要改用 shutdown() 清理原生宿主持有的实例。

如果 autoTrack.scenes 为 false,enterCocos() 必须传入 viewName,SDK 会手动创建一个 Cocos View。开启场景自动跟踪后,viewName 用作进入时的初始 View,后续场景切换由场景名接管。

View 与 Replay 所有权

页面切换时的所有权顺序如下:

时机 RUM View Session Replay 捕获源
原生页面可见 原生自动或手动 View 原生 recorder
调用 enterCocos() 停止可能存在的容器 View,启动一个 Cocos View 先暂停原生 recorder,再开始 Cocos Canvas 捕获
Cocos 页面可见 Cocos 场景或指定 View Cocos external recorder
调用 leaveCocos() 停止 Cocos View 先停止 Cocos 捕获和在途帧,再恢复原生 recorder
返回原生页面 原生自动或手动 View 原生 recorder

原生全屏弹层、登录页或其他页面即使没有销毁 Cocos 页面,只要完全覆盖 Cocos,也必须在展示前通过业务生命周期通知 Cocos 调用 leaveCocos();弹层关闭且 Cocos 再次可见后调用 enterCocos()。仅暂停 Cocos 渲染不能完成 RUM View 和 Replay 所有权转移。

同一时刻应只有一个有效 RUM View 和一个 Replay 捕获源。不要同时让原生自动跟踪与 Cocos 自动跟踪记录专用 Cocos 容器,也不要手动调用 guanceSdk.replay.start() 或 stop() 控制 attached Replay。

嵌入式 Cocos Surface

如果 Cocos 只占原生 Activity 或 UIViewController 的局部区域,当前 Native SDK 无法自动暂停并恢复宿主控制器的 View。该场景需要宿主关闭该页面的原生自动 View 跟踪,并自行使用手动 RUM API 管理宿主 View 与 Cocos View 的先后关系:进入前结束宿主 View,离开后重新启动宿主 View。

在 Native SDK 提供作用域化的 View 抑制和恢复接口前,不要仅根据 Cocos 引擎暂停、恢复回调推断 View 所有权。

验证接入

建议在 Android 和 iOS 真机上分别执行至少三轮 原生页面 -> Cocos 页面 -> 原生页面:

  1. 每次进入 Cocos 前调用 enterCocos(),离开或被完全覆盖前调用 leaveCocos()。
  2. 检查原生日志中没有 SDK 重复初始化、缺少 Hybrid recorder 接口或 Replay 未以原生模式初始化的错误。
  3. 在 RUM 查看器确认每个时段只有一个 View,Cocos 场景没有同名原生容器 View。
  4. 打开 Session Replay,确认原生页面与 Cocos 页面连续可播放,边界没有双重画面、空白帧或离开后的 Cocos 残留帧。
  5. 检查 Cocos Action、Resource、Error,以及与 RUM 关联的 Log 和 Trace 数据。

常见错误:

错误 处理方式
The native host must install the native SDK before FTCocosSDK.attach() 将原生 SDK 初始化提前到 attach() 之前
The native host must initialize the native SDK before FTCocosSDK.attach() 将 iOS 原生 SDK 初始化提前到 attach() 之前
The native host owns ... in Hybrid mode 删除 Cocos 侧的 SDK/RUM/Logger/Trace 初始化或关闭调用,仅保留原生初始化与 attach()
Hybrid Replay is managed by enterCocos() and leaveCocos() 不要直接调用 guanceSdk.replay.start() 或 stop(),改由 Cocos 页面生命周期控制
does not support Hybrid recorder switching 按SDK 版本与依赖要求核对原生依赖,并重新生成、编译原生工程
Session Replay must be initialized by the native host in native recorder mode 在原生宿主初始化 Replay,并关闭 external-only 模式
Call attach() before enterCocos() 确保 Cocos 页面加载阶段先调用一次 attach()
enterCocos.viewName is required when scene tracking is disabled 传入 viewName,或开启 autoTrack.scenes

文档评价

文档内容是否对您有帮助?