콘텐츠로 이동

네이티브와 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()
네이티브 앱에서 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만 수집하는 경우 Replay를 설치할 필요 없이 기본 패키지의 attach({ autoTrack })를 바로 사용할 수 있습니다.

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가 관리합니다.

touchPrivacy는 Cocos 페이지 Replay에서 터치 위치 기록 여부만 제어합니다. 네이티브 페이지는 계속 호스트의 Session Replay 개인정보 보호 설정을 사용합니다. 선택 가능한 값, 기본 동작 및 개인정보 보호 주의사항은 Cocos Creator 세션 리플레이를 참조하세요.

네이티브 호스트는 현재 SDK 버전 조합을 사용합니다. 함께 제공되는 Android/iOS SDK는 Hybrid Replay를 지원하며, Cocos 페이지 진입 및 이탈 시 네이티브와 Cocos 화면 캡처를 전환할 수 있습니다.

네이티브 호스트 초기화

Cocos npm/ZIP 설치 패키지에는 TypeScript API, Creator 확장 및 Android/iOS용 FTCocosBridge가 이미 포함되어 있어 호스트 프로젝트에 초기화 헬퍼 클래스를 추가로 넣을 필요가 없습니다.선택 사항인 Replay 패키지는 FTCocosReplayBridge와 이미지 처리 코드를 제공하며, 두 Bridge는 호스트가 사용하는 동일한 버전의 네이티브 SDK를 공유합니다.

Android/iOS 앱은 각 네이티브 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 계층이 네트워크 요청을 수집하면서, 호스트의 OkHttp 등의 요청에 사용되는 네이티브 Resource 전체 스위치는 유지됩니다.

충돌 원인: 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.enableTraceURLConnectionResourceFTTraceConfig.enableAutoTraceURLConnection으로 활성화하며 기본값은 모두 NO입니다. 이 두 스위치는 NSURLSessionenableTraceUserResourceenableAutoTrace와 독립적입니다. 버전만 업그레이드하거나 기존 스위치를 켜는 것만으로는 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와 네이티브를 동시에 켜면 HTTP 요청 3회에 대해 Resource 6건이 생성되고, 한 계층만 켜면 모두 3건이 생성됩니다. 동시에 켠 경우 두 레코드의 Trace ID/Span ID가 서로 다르며, 서버가 수신하는 것은 네이티브 계층이 주입한 요청 헤더입니다.

Creator 3.8.8의 경우 NSURLConnection 전용 스위치를 꺼도 NSURLSession 경로의 중복을 피할 수 없습니다. 호스트가 NSURLSession 자동 수집을 이미 켠 경우 Cocos autoTrack.networkfalse로 설정하여 네이티브 계층에서 통합 수집할 수 있습니다. 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.scenesfalse인 경우 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 컨테이너를 기록하게 하지 말고, attached Replay를 제어하기 위해 guanceSdk.replay.start() 또는 stop()을 수동으로 호출하지 마세요.

임베디드 Cocos Surface

Cocos가 네이티브 Activity 또는 UIViewController의 일부 영역만 차지하는 경우, 현재 Native SDK는 호스트 컨트롤러의 View를 자동으로 일시 중지하고 복원할 수 없습니다. 이 시나리오에서는 호스트가 해당 페이지의 네이티브 자동 View 추적을 끄고, 수동 RUM API를 사용하여 호스트 View와 Cocos View의 순서 관계를 직접 관리해야 합니다. 진입 전에 호스트 View를 종료하고, 이탈 후 호스트 View를 다시 시작합니다.

Native SDK가 범위 지정된 View 억제 및 복원 인터페이스를 제공하기 전까지, Cocos 엔진의 일시 중지·복원 콜백만으로 View 소유권을 판단하지 마세요.

연동 검증

Android와 iOS 실기기에서 각각 최소 3회 네이티브 페이지 -> 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를 켭니다

문서 평가

이 페이지가 도움이 되었나요?