본문으로 건너뛰기

Unity SDK

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

호환성

환경지원 버전
Unity2022.3 LTS 이상
플랫폼Android · iOS · Windows
언어C#
패키지com.crossx.sdk.unity (UPM)

설치

방법 A — Scoped Registry

Packages/manifest.json에 레지스트리와 패키지를 추가합니다:

{
"scopedRegistries": [
{
"name": "NexusCROSSxUPM",
"url": "https://registry.npmjs.org",
"scopes": ["com.crossx"]
}
],
"dependencies": {
"com.crossx.sdk.unity": "<version>"
}
}

방법 B — Git URL

Window → Package Manager → Add package from git URL:

https://github.com/to-nexus/crossy-sdk-unity.git?path=src/CROSSx.Sdk.Unity#<version>

Webkit SDK(com.crossx.webkit.sdk.unity)는 번들 의존성으로 자동 설치됩니다.

Project ID 설정

SDK는 Assets/Resources/CROSSx SDK Settings.asset에서 Project ID를 읽습니다. Unity 메뉴에서 생성합니다:

CROSSx SDK → Open Settings

CROSSx 콘솔에서 발급받은 Project ID를 입력합니다. 빌드 후처리기가 이 값을 사용해 딥링크 URI 스킴을 주입하며, 값이 비어 있으면 빌드가 실패합니다.

사전 준비

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

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

결제 흐름

한 줄 요약

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

Quick Start

using CROSSx.Sdk.Unity.SDK;
using CROSSx.Sdk.Unity.Core.Types;
using CROSSx.Sdk.Unity.Core.Utils;

// 1. SDK 초기화 (GameManager.Start 등에서 1회 호출)
var config = new SDKConfig
{
ProjectId = "YOUR_PROJECT_ID",
AppName = "My Game",
};
var sdk = CROSSxSDKFactory.Create(config);
await sdk.InitializeAsync();

// 2. 게임 서버에서 checkout을 생성하고 이 값들을 받아옵니다
string checkoutUrl = await MyGameServer.CreateCheckoutAsync(order);
string checkoutId = ExtractCheckoutId(checkoutUrl); // 또는 서버에서 별도로 수신

// 3. SDK가 WebView를 열고 딥링크 콜백을 대기
CrossPayCallbackResult result = await sdk.OpenCrossPayAndWaitResultAsync(
checkoutUrl,
checkoutId
);

// 4. 콜백 엔벨로프 상태 확인 (참고용)
if (result.IsSuccess)
Debug.Log("콜백 수신: success — 서버 webhook 확정 대기 중.");
else if (result.IsCancel)
Debug.Log("사용자가 결제창을 닫았습니다.");
else
Debug.LogWarning($"콜백: {result.Status} — {result.Error}");

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

딥링크 설정

결제 WebView는 모바일에서 webkit-{ProjectId} URI 스킴으로, 데스크톱에서는 로컬 루프백 URL로 리다이렉트됩니다.

Android

Assets/Plugins/Android/AndroidManifest.xml에 intent filter를 추가합니다:

<activity
android:name="com.unity3d.player.UnityPlayerActivity"
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

SDK의 iOSBuildPostProcessor가 빌드 후 URI 스킴을 자동 등록합니다. 수동 등록 시 Project Settings → Supported URL schemeswebkit-YOUR_PROJECT_ID를 추가합니다.

Windows

빌드 후 자동 생성되는 register_deeplink.reg를 1회 실행하면 루프백 콜백 핸들러가 Windows 레지스트리에 등록됩니다.

SDK 초기화

var config = new SDKConfig
{
ProjectId = "YOUR_PROJECT_ID",
AppName = "My Game",
Environment = SDKEnvironment.Development, // URL 자동 설정
Theme = ThemeMode.Dark,
Locale = "ko",
Debug = true,
};

var sdk = CROSSxSDKFactory.Create(config);

// 저장된 세션이 있으면 복원
var session = await sdk.InitializeAsync();
if (session != null)
Debug.Log($"세션 복원: {session.WalletAddress}");
노트

SDKEnvironment.Development는 API URL을 자동으로 결정합니다. OAuthServerUrl, AuthApiUrl, EmbeddedWalletGatewayUrl을 직접 지정하려면 SDKEnvironment.Custom을 사용합니다.

결제 실행

CrossPayCallbackResult result = await sdk.OpenCrossPayAndWaitResultAsync(
checkoutUrl: checkoutUrl,
checkoutId: 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 내에 콜백이 도착하지 않으면 TimeoutException을 throw합니다.

결과 처리

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

필드타입설명
Statusstring엔벨로프 상태: "success" | "cancel" | "failed" (또는 PG 원시값)
IsSuccessboolStatus == "success"이면 true
IsCancelboolStatus == "cancel"이면 true
IsFailedboolStatus == "failed"이면 true
DataJObject?PG 결제 데이터 — 제공자마다 필드 다름
Errorstring?IsFailed일 때 오류 메시지
RawParamsIReadOnlyDictionary<string, string>?콜백 URL의 모든 쿼리 파라미터 (예: checkout_id, payment_id, tx_hash)
서버에서 반드시 검증하세요

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

오류 처리

try
{
var result = await sdk.OpenCrossPayAndWaitResultAsync(checkoutUrl, checkoutId);
}
catch (TimeoutException)
{
// 딥링크 콜백이 timeoutMs 내에 도착하지 않았습니다.
// 사용자가 결제를 완료했지만 콜백이 앱에 도달하지 못했을 수 있습니다.
// 서버에서 결제 상태를 확인하세요.
bool paid = await MyGameServer.VerifyPaymentAsync(checkoutId);
}
catch (InvalidOperationException ex)
{
// SDK 미초기화 또는 WebView 실행 실패.
Debug.LogError(ex.Message);
}

멱등성

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

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