ネイティブと 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 を使用します。まずアプリ接入に従って、同じバージョンの 2 つの 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 が管理します。
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 と画像処理コードを提供し、2 つの 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 の初期化前に以下を設定します。
これにより、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 です。これらの 2 つのスイッチは、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 の初期化前に上記の 2 つの専用スイッチを YES に設定し、同時に Cocos の autoTrack.network をオフにします。JS で他のリクエストを収集する必要がある場合は、ネイティブの resourceUrlHandler を使用して URL ごとに重複リクエストを除外し(YES を返すと Resource を収集しない)、Trace 注入ポリシーは別途確認してください。Resource のフィルタリングによって Trace 注入がオフになることはありません。
Creator 3.8.8 / iOS の実際の XHR 比較では、JS とネイティブの両方を有効にした場合、3 回の HTTP リクエストに対して 6 件の Resource が生成されました。いずれか一方のレイヤーのみを有効にした場合は、どちらも 3 件でした。両方を有効にした場合、2 つのレコードの 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 数を 1 対 1 で対応付け、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 キャプチャソースは、それぞれ 1 つだけである必要があります。ネイティブの自動追跡と 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 の実機で、それぞれ少なくとも 3 回の ネイティブページ -> Cocos ページ -> ネイティブページ のフローを実行することを推奨します。
- Cocos に入る前に毎回
enterCocos()を呼び出し、離脱または完全に覆われる前にleaveCocos()を呼び出します。 - ネイティブログに、SDK の重複初期化、Hybrid recorder インターフェースの欠落、Replay がネイティブモードで初期化されていない、などのエラーがないことを確認します。
- RUM エクスプローラーで、各時間帯に View が 1 つだけであること、Cocos シーンに同名のネイティブコンテナ View がないことを確認します。
- Session Replay を開き、ネイティブページと Cocos ページが連続して再生可能であり、境界に二重画面、空白フレーム、離脱後の Cocos 残存フレームがないことを確認します。
- 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 を有効にする |