본문으로 건너뛰기

Cocos Creator SDK

CROSS Pay 결제 연동을 위한 공식 Cocos Creator SDK입니다. 인앱 WebView로 결제 세션을 열고, 딥링크 콜백을 수신한 뒤 결과를 반환합니다 — API 키는 클라이언트에 존재하지 않습니다.

호환성

환경지원 버전
Cocos Creator3.8.8+
플랫폼Android · iOS · Windows · Web
언어TypeScript
패키지com.crossx.sdk.cocos (npm)
모듈 형식ESM · CJS
Node.js18+

설치

SDK는 npmjs.org에 배포되며, postinstall 동기화 스크립트를 통해 Cocos 프로젝트 구조(extensions/ 빌드 훅, assets/ 런타임 코드)에 자동으로 미러됩니다.

1. package.json에 의존성 추가

{
"scripts": {
"postinstall": "node scripts/sync-crossx-sdk.js",
"sync-sdk": "node scripts/sync-crossx-sdk.js",
"clean-sdk": "node scripts/sync-crossx-sdk.js --clean"
},
"dependencies": {
"com.crossx.sdk.cocos": "0.0.0-beta.15"
}
}

버전 번호를 최신 릴리스로 업데이트합니다.

2. 동기화 스크립트 복사

샘플 프로젝트에서 scripts/sync-crossx-sdk.js를 프로젝트의 scripts/ 디렉터리에 복사합니다. 이 스크립트가 npm install 후 SDK를 extensions/assets/에 미러합니다.

3. 설치 실행

npm install

postinstall 훅이 자동으로 실행되어 SDK를 동기화합니다. Cocos Creator를 재시작해 익스텐션을 로드합니다.

버전 업그레이드 시 package.json의 버전만 수정하고 npm install을 다시 실행합니다.

트러블슈팅

익스텐션이 로드되지 않거나 import가 인식되지 않으면 npm run clean-sdk && npm install 후 Cocos Creator를 완전히 종료했다가 다시 엽니다.

Project ID 설정

1. 설정 파일 생성

샘플 프로젝트settings/crossx-sdk.example.jsonsettings/crossx-sdk.json으로 복사하고 Project ID를 입력합니다:

{
"activeEnvironment": "prod",
"prodProjectId": "YOUR_PROJECT_ID",
"prodOnly": true
}

CROSSx 콘솔에서 Project ID를 발급받습니다. settings/crossx-sdk.json.gitignore에 추가합니다.

2. 런타임에서 읽기

import { CROSSxCocosSDKFactory } from '../CROSSx.Sdk.Cocos/assets/index';

const sdk = CROSSxCocosSDKFactory.create({
projectId: 'YOUR_PROJECT_ID',
});

빌드 훅이 빌드 시 settings/crossx-sdk.json을 읽어 딥링크 URI 스킴을 네이티브 프로젝트에 주입합니다. prodProjectId가 비어 있으면 빌드가 실패합니다.

사전 준비

모든 예시의 checkoutUrl / checkoutId게임 서버POST /v1/payments를 호출해 발급받은 뒤 클라이언트로 전달한 값입니다.

  • MERCHANT_API_KEY는 서버 환경변수 또는 secret manager에만 저장합니다.
  • 게임 클라이언트는 서버로부터 checkout_urlcheckout_id만 수신합니다.
  • 딥링크 콜백 결과는 주문 확정 근거가 아닙니다. 최종 처리는 webhook 또는 서버 조회(GET /v1/payments/{id})로 확정하세요.

결제 흐름

한 줄 요약

게임 서버가 결제 세션을 생성 → SDK가 WebView를 열고 딥링크 콜백을 대기 → 서버가 webhook으로 주문을 최종 확정합니다. 딥링크 콜백 결과는 확정의 근거가 아닙니다.

Quick Start

import { CROSSxCocosSDKFactory, CocosSdkModalUI, type CrossPayCallback } from '../CROSSx.Sdk.Cocos/assets/index';

// 1. SDK 인스턴스 생성 (onLoad 등에서 1회 호출)
const sdk = CROSSxCocosSDKFactory.create({
projectId: 'YOUR_PROJECT_ID',
appName: 'My Game',
debug: true,
});

// SDK 소유 UI 모달(서명 확인, WebView 등)에 필요합니다
sdk.setUIProvider(new CocosSdkModalUI(this.node));

await sdk.initialize();

// 2. 게임 서버에서 checkout을 생성하고 이 값들을 받아옵니다
const { checkoutUrl, checkoutId } = await myGameServer.createCheckout(order);

// 3. SDK가 WebView를 열고 딥링크 콜백을 대기
const callback: CrossPayCallback = await sdk.openCrossPayAndWaitResult(
checkoutUrl,
checkoutId,
{ timeoutMs: 300_000 }
);

// 4. 콜백 엔벨로프 상태 확인 (참고용)
if (callback.status === 'success')
console.log('콜백 수신: success — 서버 webhook 확정 대기 중.');
else if (callback.status === 'cancel')
console.log('사용자가 결제창을 닫았습니다.');
else
console.warn('콜백:', callback.status, callback.error);

// 5. 재화 지급 전 서버에서 최종 결제 상태를 반드시 확인합니다
const paid = await myGameServer.verifyPayment(checkoutId);

딥링크 설정

빌드 훅이 settings/crossx-sdk.jsonprodProjectId를 읽어 Android 및 iOS 빌드 시 webkit-{projectId} URI 스킴을 네이티브 프로젝트에 자동으로 주입합니다. AndroidManifest.xml이나 Info.plist를 수동으로 편집할 필요가 없습니다.

참고로 훅이 주입하는 내용은 다음과 같습니다:

Android

AndroidManifest.xmlAppActivity에 추가되는 intent filter:

<activity android:name="com.cocos.game.AppActivity"
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="webkit-YOUR_PROJECT_ID" />
</intent-filter>
</activity>

iOS

Info.plistURL Typeswebkit-YOUR_PROJECT_ID 추가.

Windows

SDK가 로컬 HTTP 리스너를 통해 루프백 콜백 핸들러를 자동으로 처리합니다.

SDK 초기화

import { CROSSxCocosSDKFactory } from '../CROSSx.Sdk.Cocos/assets/index';

const sdk = CROSSxCocosSDKFactory.create({
projectId: 'YOUR_PROJECT_ID',
appName: 'My Game',
defaultChainId: 'eip155:612044',
theme: 'dark',
locale: 'ko',
debug: true,
});

// 저장된 세션이 있으면 복원
const session = await sdk.initialize();
if (session?.success)
console.log('세션 복원:', session.address);

결제 실행

const callback = await sdk.openCrossPayAndWaitResult(
checkoutUrl,
checkoutId,
{ timeoutMs: 300_000 } // 기본값: 5분
);

SDK 동작 순서:

  1. checkoutUrl에 CSRF state 토큰과 콜백 엔드포인트를 추가합니다.
  2. 플랫폼 기본 WebView로 결제 페이지를 엽니다.
  3. 결제 콜백 수신을 대기합니다 — 플랫폼별로 방식이 다릅니다:
    • Android · iOS · macOS: 딥링크 스킴 webkit-{projectId}://crosspay-callback
    • Windows · Editor: 루프백 HTTP http://localhost:{port}/crosspay-callback
  4. state를 검증하고 디코딩된 콜백 엔벨로프를 반환합니다.
  5. timeoutMs 내에 콜백이 도착하지 않으면 에러를 throw합니다.

결과 처리

CrossPayCallback은 딥링크 콜백 엔벨로프를 담고 있습니다.

필드타입설명
statusstring엔벨로프 상태: 'success' | 'cancel' | 'failed' (또는 PG 원시값)
statestring?CSRF state 에코값
dataCrossPayPayment?PG 결제 데이터 — 제공자마다 필드 다름
errorstring?status === 'failed'일 때 오류 메시지
rawParamsRecord<string, string>?콜백 URL의 모든 쿼리 파라미터 (예: checkout_id, payment_id, tx_hash)
서버에서 반드시 검증하세요

딥링크 콜백 결과는 참고용입니다. 재화 지급 전 서버에서 GET /v1/payments/{id} 조회 또는 webhook으로 결제 상태를 반드시 확인하세요.

// 콜백에서 PG 제공 필드 읽기
const checkoutId = callback.data?.checkout_id ?? callback.rawParams?.checkout_id;
const txHash = callback.rawParams?.tx_hash;

console.log('PG 상태:', callback.data?.status);

오류 처리

import { CROSSxCocosError } from '../CROSSx.Sdk.Cocos/assets/index';

try {
const callback = await sdk.openCrossPayAndWaitResult(checkoutUrl, checkoutId);
} catch (error) {
if (error instanceof Error && error.message.includes('timed out')) {
// 딥링크 콜백이 timeoutMs 내에 도착하지 않았습니다.
// 사용자가 결제를 완료했지만 콜백이 앱에 도달하지 못했을 수 있습니다.
const paid = await myGameServer.verifyPayment(checkoutId);
} else if (error instanceof CROSSxCocosError) {
console.error(error.code, error.message);
} else {
throw error;
}
}

딥링크 이벤트 구독

모든 딥링크 이벤트에 대한 커스텀 처리가 필요한 경우:

const unsubscribe = sdk.onDeepLink((event) => {
console.log('딥링크 수신:', event.url, event.callbackType);
// callbackType: 'oauth' | 'crosspay' | 'webkit' | 'unknown'
});

// 더 이상 필요 없을 때 구독 해제
unsubscribe();

Web 플랫폼에서는 OAuth 콜백 URL을 수동으로 전달합니다:

sdk.handleOAuthCallback(window.location.href);

멱등성

시나리오동작
같은 세션 내 재시도 (네트워크 장애, WebView 재실행 등)동일 checkoutId 재사용 — 같은 checkoutUrlcheckoutIdopenCrossPayAndWaitResult 재호출
결제가 터미널 상태(PAID / FAILED / EXPIRED / CANCELLED)에 도달폐기 — 서버에서 POST /v1/payments를 호출해 새 checkout을 발급합니다
다른 주문 / 금액 / 플레이어의 새 결제항상 새 checkout — 이전 checkoutId 재사용 시 금액 불일치로 거부될 수 있습니다
환불 없음

CROSS Pay는 현재 환불 기능을 제공하지 않습니다. 동일 주문이 두 번 결제되면 되돌릴 수 없습니다. 재시도 시 동일 Idempotency-KeyPOST /v1/payments를 호출하세요.