Skip to content

Native and Cocos Hybrid Development

This document describes how to integrate the SDK in scenarios where native and Cocos are used in hybrid development. It applies to apps that are primarily built with Android/iOS native pages and use Cocos Creator for some pages. The native host is responsible for initializing the observability SDK. Cocos takes over the Cocos-layer RUM View, automatic collection, and Session Replay frame capture only while its own pages are visible.

The current automatic management scope only supports standalone Cocos Activity or UIViewController. For a Cocos Surface embedded in a local area of a native page, the host must manually manage the RUM View. Automatic replacement and restoration of the host page's View are not supported.

Integration Boundaries

Apps in which Cocos drives the entire application and apps that use native and Cocos in hybrid development use different initialization entry points:

Scenario Initialization Entry Point Configuration Owner Termination Method
The entire app is driven by Cocos guanceSdk.start() Cocos guanceSdk.shutdown()
Native app partially uses Cocos Call guanceSdk.attach() after native SDK initialization Native host Cocos page calls 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 avoid re-initializing or shutting down 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 as described in App Integration; see Cocos Lifecycle Integration below for the specific imports. If you only need to collect Cocos RUM, Log, and Trace, you can use attach({ autoTrack }) from the base package directly without installing Replay.

attach() only accepts Cocos capture and automatic 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 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 re-initialize 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 for Cocos pages records touch positions; native pages continue to use the host's Session Replay privacy configuration. See Cocos Creator Session Replay for the allowed values, default behavior, and privacy considerations.

The native host must configure a native SDK that matches the installed npm packages, as described in SDK Version and Dependency Requirements. The matching Android/iOS SDK supports Hybrid Replay, which switches between native and Cocos frame capture when entering and leaving Cocos pages.

Initialize the Native Host

The Cocos npm/ZIP package already includes the TypeScript API, the Creator extension, and the Android/iOS FTCocosBridge. You do not need to add extra initialization helper classes to 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.

The Android/iOS app initializes the required RUM, Logger, Trace, and Session Replay according to the integration requirements of each native SDK, and ensures that initialization is complete before the first call to guanceSdk.attach(). For the specific configuration, see:

The iOS host can switch dependency management methods as described in SPM Integration. The host and the Cocos Bridge should use the same native SDK; avoid importing it through both CocoaPods and SPM. The Hybrid example in the repository reads the same cocos-sdk.config.json; after updating the local extension and regenerating the iOS project, continue to run the example's existing native:install command, and the installer links the Bridge and HybridSampleHost through SPM. The host initialization and the Cocos attach() flow remain unchanged.

For a standalone Cocos Activity or UIViewController, you do not need to modify the native SDK initialization flow for Hybrid integration. When the Cocos page is displayed and when it is left, call enterCocos() and leaveCocos() respectively to switch the RUM View and the Replay capture source.

If Session Replay is enabled, the native host must be initialized using the default native recorder mode; do not set it to 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 that version or a later version.

We recommend enabling Cocos autoTrack.network: true and keeping native HttpURLConnection automatic collection disabled (disabled by default). The native host configures the following before initializing RUM:

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

This way, network requests are collected by the Cocos JS layer while the native Resource master switch remains on 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; Creator 2 uses Cocos2dxHttpURLConnection and Creator 3 uses CocosHttpURLConnection. If both JS and native HttpURLConnection collection are enabled, the same request is reported as separate Resources. There is no cross-layer deduplication between the two layers, and injecting Trace Headers from both layers 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 through FTRumConfig.enableTraceURLConnectionResource and FTTraceConfig.enableAutoTraceURLConnection respectively. Both default to NO. These two switches are independent of enableTraceUserResource and enableAutoTrace, which are used for NSURLSession; merely upgrading the version 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 Resources 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 you should not directly apply the Android conclusion that enabling both layers overwrites the Trace Header.

For Creator 2, we recommend keeping Cocos autoTrack.network: true, leaving the native dedicated switches off, and retaining 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 initializing native RUM / Trace, and disable Cocos autoTrack.network at the same time. If you still need JS to collect other requests, you can use the native resourceUrlHandler to exclude overlapping requests by URL (returning YES means the Resource is not collected), and confirm the Trace injection policy separately; 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 generate 6 Resources; when only either layer is enabled, there are 3 in both cases. When both are 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, turning off the dedicated NSURLConnection switches does not avoid duplication on the NSURLSession path. If the host has already enabled NSURLSession automatic collection, you can set Cocos autoTrack.network to false so the native layer performs collection uniformly. If you keep JS collection, you need to avoid native Resource collection covering the same requests while preserving the collection needs of the host's other network requests.

When business code manually calls startResource / stopResource / addResource, it must also 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; it cannot bypass native collection.

During verification, add a unique request_id to each request, map the actual number of HTTP requests one-to-one to the number of uploaded Resources, and check the HTTP status, duration, and Trace ID / Span ID. The page showing a successful request is not enough to prove that automatic Resource collection succeeded.

Cocos Lifecycle Integration

The following examples use Creator 3; for Creator 2, change the import paths 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();
}

The first Camera found in the current scene is used by default. In projects with multiple Cameras, pass the Camera used for replay to attachObservability(camera), and call guanceSdk.setReplayCamera(camera) again after switching the main Camera.

attach(), enterCocos() after already entering, and leaveCocos() after already leaving are all idempotent operations. The destroy path can call leaveCocos() again to cover abnormal exits or duplicate callbacks.

If the recorder switch fails, the relevant call throws 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; the SDK then manually creates a Cocos View. When automatic scene tracking is enabled, viewName is used as the initial View when entering, and subsequent scene switches are handled by the scene name.

View and Replay Ownership

The ownership sequence during page switching is as follows:

Timing RUM View Session Replay Capture Source
Native page visible Native automatic or manual View Native recorder
Call enterCocos() Stop the container View if one exists, and start a Cocos View Pause the native recorder first, then start Cocos Canvas capture
Cocos page visible Cocos scene or specified View Cocos external recorder
Call leaveCocos() Stop the Cocos View Stop the Cocos capture and in-flight frames first, then resume the native recorder
Return to native page Native automatic or manual View Native recorder

Native full-screen overlays, login pages, or other pages must notify Cocos through the business lifecycle to call leaveCocos() before they are shown if they completely cover Cocos, even if the Cocos page is not destroyed; call enterCocos() after the overlay is closed and Cocos is visible again. Merely pausing Cocos rendering does not complete the transfer of RUM View and Replay ownership.

At any given time, there should be only one active RUM View and one Replay capture source. Do not let native automatic tracking and Cocos automatic tracking both record the dedicated Cocos container, and do not manually call guanceSdk.replay.start() or stop() to control the attached Replay.

Embedded Cocos Surface

If Cocos occupies only a local 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 automatic View tracking for that page and use the manual RUM API to manage the sequence between 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.

Verify the Integration

We recommend running at least three rounds of Native page -> Cocos page -> Native page on Android and iOS physical devices respectively:

  1. Call enterCocos() before entering Cocos each time, and call leaveCocos() before leaving or being completely covered.
  2. Check that the native logs do not contain errors about duplicate SDK initialization, missing Hybrid recorder interfaces, or Replay not initialized in native mode.
  3. In the RUM Explorer, confirm that there is only one View in each time period and that Cocos scenes do not have native container Views with the same name.
  4. Open Session Replay and confirm that the native and Cocos pages can be played back continuously, with no double frames, blank frames, or Cocos residual frames after leaving at the boundaries.
  5. Check Cocos Actions, Resources, and Errors, 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 to before attach()
The native host must initialize the native SDK before FTCocosSDK.attach() Move iOS native SDK initialization to before attach()
The native host owns ... in Hybrid mode Remove the SDK/RUM/Logger/Trace initialization or shutdown calls on the Cocos side, and keep only the 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 it instead
does not support Hybrid recorder switching Check the native dependencies against SDK Version and Dependency Requirements, then 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 turn off external-only mode
Call attach() before enterCocos() Make sure attach() is called once during the Cocos page loading stage
enterCocos.viewName is required when scene tracking is disabled Pass a viewName, or enable autoTrack.scenes

Feedback

Is this page helpful?