Native and Cocos Hybrid Development¶
This document describes SDK integration for native and Cocos hybrid development scenarios. It applies to apps that are primarily Android/iOS native pages, with some pages built with Cocos Creator. The native host initializes the observability SDK, and Cocos takes over the RUM View, automatic collection, and Session Replay frame capture on the Cocos side only while its own pages are visible.
The current scope of automatic management only supports standalone Cocos Activity or UIViewController instances. A Cocos Surface embedded in a partial area of a native page requires the host to manually manage the RUM View; automatic replacement and restoration of the host page View is not supported.
Integration Boundaries¶
Standalone Cocos apps and apps developed with native and Cocos hybrid development use different initialization entry points:
| Scenario | Initialization Entry Point | Configuration Owner | Termination Method |
|---|---|---|---|
| Entire app driven by Cocos | guanceSdk.start() |
Cocos | guanceSdk.shutdown() |
| Native app partially using Cocos | Call guanceSdk.attach() after the native SDK is initialized |
Native host | Cocos pages call guanceSdk.leaveCocos() |
start() and attach() are mutually exclusive. After entering Hybrid mode, the SDK rejects calls from the Cocos side to mobile.start(), rum.start(), logger.start(), trace.start(), replay.start(), replay.stop(), and shutdown() to prevent repeated initialization or shutdown of the SDK owned by the native host. Non-initialization APIs such as user binding, RUM events, log writes, and Trace Headers remain available through the bridge.
The Replay examples on this page use the guanceSdk returned by withSessionReplay(baseSdk). First install the two same-version npm packages and run --replay according to App Integration; see Integrating the Cocos Lifecycle below for the specific imports. When collecting only Cocos RUM, Log, and Trace, you can directly use attach({ autoTrack }) from the base package without installing Replay.
attach() accepts only Cocos capture and auto-collection configuration:
guanceSdk.attach({
replay: {
captureFps: 1,
maxImageDimension: 720,
touchPrivacy: 'show',
},
autoTrack: {
scenes: true,
actions: true,
errors: true,
network: true,
},
});
attach() uses FTCocosBridge to confirm that the native host has already initialized the SDK, and appends the sdk_package_cocos version information to the native global context. It does not pass the reporting endpoint, RUM App ID, or sampling rate, nor does it reinitialize any native modules.
Sampling decisions, sessions, data storage, and global configuration for Replay and RUM continue to be managed by the native SDK.
touchPrivacy only controls whether Replay on Cocos pages records touch positions; native pages continue to use the host's Session Replay privacy configuration. See Cocos Creator Session Replay for allowed values, default behavior, and privacy considerations.
The native host uses the current SDK version combination. The matching Android/iOS SDK supports Hybrid Replay, switching between native and Cocos frame capture when entering and leaving Cocos pages.
Initializing the Native Host¶
The Cocos npm/ZIP package already includes the TypeScript API, the Creator extension, and the FTCocosBridge for Android/iOS, so no additional initialization helper classes are needed in the host project.The optional Replay package provides FTCocosReplayBridge and image processing code; both Bridges share the same version of the native SDK used by the host.
Initialize the required RUM, Logger, Trace, and Session Replay components in the Android/iOS app according to the integration requirements of the respective native SDK, and ensure initialization is complete before the first call to guanceSdk.attach(). See the following for specific configuration:
iOS hosts can switch dependency management methods as described in SPM Integration. The host and Cocos Bridge should use the same native SDK; avoid introducing the same SDK through both CocoaPods and SPM. The Hybrid sample in the repository reads the same cocos-sdk.config.json; after updating the local extension and regenerating the iOS project, continue running the sample's original native:install command, and the installer links the Bridge and HybridSampleHost through SPM. The host initialization and Cocos attach() flow remain unchanged.
For standalone Cocos Activity or UIViewController instances, you do not need to rewrite the native SDK initialization flow for Hybrid integration. When a Cocos page is displayed or left, call enterCocos() or leaveCocos() respectively to switch the RUM View and Replay capture source.
If Session Replay is enabled, the native host must initialize with the default native recorder mode, not external-only. The Cocos side only passes frame capture configuration in attach().
Android Network Collection Recommendations¶
HttpURLConnection automatic collection is supported starting with Android Agent 1.7.6-alpha03 together with Android Gradle Plugin 1.3.9-alpha01; both components must use these versions or later.
Enable Cocos autoTrack.network: true and keep native HttpURLConnection automatic collection disabled (disabled by default). Configure the native host before initializing RUM:
This way, network requests are collected by the Cocos JS layer while the native Resource master switch remains enabled for requests such as the host's OkHttp.
Reason for the conflict: On Android, Cocos JS XHR goes through the engine's HttpURLConnection wrapper underneath, corresponding to Cocos2dxHttpURLConnection in Creator 2 and CocosHttpURLConnection in Creator 3. When both JS and native HttpURLConnection collection are enabled, a Resource is reported separately for the same request from each layer; there is no cross-layer deduplication. Injecting Trace Headers from both layers at the same time can also cause the Resource's Trace information to be inconsistent with the request headers received by the server.
iOS Network Collection Recommendations¶
iOS SDK 1.6.8-alpha.5 adds automatic Resource collection and Trace correlation for NSURLConnection, enabled by FTRumConfig.enableTraceURLConnectionResource and FTTraceConfig.enableAutoTraceURLConnection respectively, both defaulting to NO. These two switches are independent of enableTraceUserResource and enableAutoTrace, which are used for NSURLSession; upgrading the version alone or turning on the existing switches does not enable NSURLConnection collection.
First confirm the actual request implementation of the current engine, then choose the collection layer:
| iOS request path | Native Resource switch | Native Trace switch |
|---|---|---|
Creator 2.4.9 / 2.4.15 XHR: NSURLConnection |
enableTraceURLConnectionResource |
enableAutoTraceURLConnection |
Creator 3.8.8 XHR: NSURLSession |
enableTraceUserResource |
enableAutoTrace |
When the same Cocos XHR is covered by both autoTrack.network and the corresponding native Resource collection, the JS and native layers report a Resource separately, and there is currently no cross-layer deduplication. Identical Trace Headers do not mean the Resource has been deduplicated. NSURLConnection collection reuses existing Trace Headers it can recognize, so the Android conclusion about overwritten Trace Headers with both layers enabled should not be applied directly.
For Creator 2, keep Cocos autoTrack.network: true, leave the native dedicated switches off, and keep the host's independent NSURLSession collection:
rumConfig.enableTraceUserResource = YES;
rumConfig.enableTraceURLConnectionResource = NO;
traceConfig.enableAutoTrace = YES;
traceConfig.enableAutoTraceURLConnection = NO;
If the native layer collects NSURLConnection, set the two dedicated switches above to YES before native RUM/Trace initialization and disable Cocos autoTrack.network at the same time. If the JS layer still needs to collect other requests, use the native resourceUrlHandler to exclude overlapping requests by URL (returning YES means the Resource is not collected), and separately confirm the Trace injection strategy; Resource filtering does not disable Trace injection.
In the actual XHR comparison for Creator 3.8.8 / iOS, when both JS and native collection are enabled, 3 HTTP requests produce 6 Resource entries; enabling either layer alone produces 3. With both enabled, the Trace ID / Span ID of the two records differ, and the server receives the request headers injected by the native layer.
For Creator 3.8.8, disabling the dedicated NSURLConnection switches does not avoid duplication on the NSURLSession path. When the host already enables NSURLSession automatic collection, you can set Cocos autoTrack.network to false and let the native layer handle collection uniformly; if JS collection is retained, avoid native Resource collection covering the same requests while preserving the host's collection needs for other network requests.
When manually calling startResource / stopResource / addResource in business code, you also need to avoid the same requests covered by native automatic collection. Saving and calling XHR methods that are not wrapped by the JS SDK can only bypass JS automatic collection, not native collection.
When verifying, add a unique request_id to each request, match the actual HTTP request count one-to-one with the number of uploaded Resources, and check HTTP status, duration, and Trace ID / Span ID. The page showing a successful request is not sufficient to prove that Resource automatic collection succeeded.
Integrating the Cocos Lifecycle¶
The examples below use Creator 3; for Creator 2, change the import entry points of both the base package and the Replay package to /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();
}
Bind the lifecycle in the Cocos page component:
onLoad(): void {
attachObservability();
}
onEnable(): void {
enterCocos('Game');
}
onDisable(): void {
leaveCocos();
}
onDestroy(): void {
leaveCocos();
}
By default, the first Camera found in the current scene is used. Multi-Camera projects should pass the Camera used for replay to attachObservability(camera), and call guanceSdk.setReplayCamera(camera) again after switching the main Camera.
attach(), enterCocos() after already entered, and leaveCocos() after already left are all idempotent operations. The destruction path can call leaveCocos() again to cover abnormal exits or duplicate callbacks.
If the recorder switch fails, the related calls throw an error. After ruling out Native SDK version or initialization issues, call the current lifecycle method again to complete the enter or leave; do not use shutdown() instead to clean up the instance owned by the native host.
If autoTrack.scenes is false, enterCocos() must be passed a viewName, and the SDK manually creates a Cocos View. When scene auto-tracking is enabled, viewName is used as the initial View when entering, and subsequent scene switches are taken over by the scene name.
View and Replay Ownership¶
The ownership sequence during page switches is as follows:
| Timing | RUM View | Session Replay Capture Source |
|---|---|---|
| Native page visible | Native automatic or manual View | Native recorder |
Calling enterCocos() |
Stops the container View if present, starts a Cocos View | Pauses the native recorder first, then starts Cocos Canvas capture |
| Cocos page visible | Cocos scene or specified View | Cocos external recorder |
Calling leaveCocos() |
Stops the Cocos View | Stops Cocos capture and in-flight frames first, then resumes the native recorder |
| Returning to native page | Native automatic or manual View | Native recorder |
Even if native full-screen overlays, login pages, or other pages do not destroy the Cocos page, as long as they completely cover Cocos, they must notify Cocos through the business lifecycle to call leaveCocos() before being displayed; call enterCocos() after the overlay closes and Cocos becomes visible again. Merely pausing Cocos rendering cannot complete the RUM View and Replay ownership transfer.
At any given time, there should be exactly one active RUM View and one Replay capture source. Do not let both native auto-tracking and Cocos auto-tracking record a dedicated Cocos container at the same time, and do not manually call guanceSdk.replay.start() or stop() to control an attached Replay.
Embedded Cocos Surface¶
If Cocos occupies only a partial area of a native Activity or UIViewController, the current Native SDK cannot automatically pause and restore the host controller's View. In this scenario, the host must disable native auto View tracking for that page and use the manual RUM API to manage the ordering of the host View and the Cocos View: end the host View before entering, and restart the host View after leaving.
Until the Native SDK provides scoped View suppression and restoration interfaces, do not infer View ownership solely from Cocos engine pause and resume callbacks.
Verifying the Integration¶
Run at least three rounds of native page -> Cocos page -> native page on Android and iOS physical devices respectively:
- Call
enterCocos()before each entry into Cocos, and callleaveCocos()before leaving or being completely covered. - Check the native logs for the absence of errors about repeated SDK initialization, missing Hybrid recorder interface, or Replay not initialized in native mode.
- In the RUM Explorer, confirm that there is only one View per time period and that Cocos scenes have no native container View with the same name.
- Open Session Replay and confirm that native pages and Cocos pages play continuously, with no double frames, blank frames, or leftover Cocos frames after leaving at the boundaries.
- Check Cocos Action, Resource, and Error data, as well as Log and Trace data associated with RUM.
Common errors:
| Error | Resolution |
|---|---|
The native host must install the native SDK before FTCocosSDK.attach() |
Move native SDK initialization before attach() |
The native host must initialize the native SDK before FTCocosSDK.attach() |
Move iOS native SDK initialization before attach() |
The native host owns ... in Hybrid mode |
Remove the SDK/RUM/Logger/Trace initialization or shutdown calls on the Cocos side; keep only native initialization and attach() |
Hybrid Replay is managed by enterCocos() and leaveCocos() |
Do not call guanceSdk.replay.start() or stop() directly; let the Cocos page lifecycle control them |
does not support Hybrid recorder switching |
Check the native dependencies against the current SDK version combination, and regenerate and compile the native project |
Session Replay must be initialized by the native host in native recorder mode |
Initialize Replay in the native host and disable external-only mode |
Call attach() before enterCocos() |
Ensure attach() is called once during the Cocos page loading stage |
enterCocos.viewName is required when scene tracking is disabled |
Pass viewName, or enable autoTrack.scenes |