Unity 인앱 결제(IAP)
네임스페이스: UnityEngine.Purchasing | 보안: UnityEngine.Purchasing.Security
패키지: com.unity.purchasing
Unity IAP는 고유한 초기화 경로를 가집니다: UnityIAPServices.StoreController() → store.Connect(). UnityServices.InitializeAsync()가 필요하지 않지만, 프로젝트에서 다른 UGS 서비스를 사용한다면 함께 공존할 수 있습니다. Analytics가 있고 InitializeAsync()가 호출되면 IAP가 자동으로 트랜잭션 이벤트를 전송합니다.
시작하기 전에
먼저 항상 references/pre-check.md를 읽으십시오. 이 문서는 프로젝트에서 타사 IAP 패키지, 네이티브 Google Billing, 기존 Unity IAP 버전을 스캔한 후 올바른 경로로 안내합니다. 라우팅이 해결될 때까지 다른 참조 파일을 읽거나 변경하지 마십시오.
상세 참조
- 프로젝트 스캔 및 경로 라우팅 (먼저 읽을 것): references/pre-check.md 참조
- API 시그니처 및 코드 예제: references/api-notes.md 참조
- 플랫폼 확장 (Apple, Google): references/platform-notes.md 참조
IAPProductCatalog.json편집 (스키마, 10진수 직렬화, 새로고침): references/codeless-catalog.md 참조- v4 → v5 마이그레이션: references/migration-v4-to-v5.md 참조
- 네이티브 Google BillingClient를 Unity IAP 5로 변환: references/path-convert-native-google-billing.md 참조
- 네이티브 iOS StoreKit 플러그인을 Unity IAP 5로 변환: references/path-convert-native-storekit.md 참조
- Essential Kit 결제를 Unity IAP 5로 변환: references/convert-essentialkit.md 참조
- UniPay (FLOBUK) — 평가 및 안내: references/convert-unipay.md 참조
- RevenueCat — 전환 평가 및 안내: references/convert-revenuecat.md 참조
- Adapty — 전환 평가 및 안내: references/convert-adapty.md 참조
- 기존 IAP가 없는 프로젝트에 Unity IAP 5 추가: references/path-add-iap-to-new-project.md 참조
- IAP D2C 기능 구현 (타사 결제 제공업체 — Stripe/Coda, v5.4+ 필요): references/path-implement-iap-d2c.md 참조
참조 파일은 필요할 때만 읽으십시오 — 특정 API 시그니처, 플랫폼 확장 세부 정보 또는 마이그레이션 매핑이 필요할 때만 읽습니다.
초기화 흐름
UnityIAPServices.StoreController()를 통해StoreController를 얻습니다 (또는DefaultStore(),DefaultProduct(),DefaultPurchase()를 통해 개별 서비스 획득)Connect()호출 전에 필요한 모든 이벤트를 구독합니다 (아래 필수 이벤트 구독 참조)await store.Connect()를 호출하여 플랫폼 스토어에 연결합니다OnStoreConnected에서store.FetchProducts(List<ProductDefinition>)를 호출하여 카탈로그를 로드합니다OnProductsFetched에서 제품이 표시 및 구매 준비가 됩니다
초기화에는 Awake()를 사용하십시오 — 다른 Start() 메서드보다 IAP가 먼저 준비되도록 합니다.
제품 유형: ProductType.Consumable, ProductType.NonConsumable, ProductType.Subscription.
제품 가져오기
제품을 List<ProductDefinition>으로 정의하고 store.FetchProducts()에 전달합니다. 제품 ID가 Apple/Google 스토어마다 다를 때는 StoreSpecificIds를 사용합니다. 복잡한 카탈로그의 경우 CatalogProvider를 사용하여 제품 세트와 스토어별 ID를 관리합니다.
| 메서드 | 동작 |
|---|---|
GetProducts() | 캐시된 제품 목록을 반환합니다 (동기식, FetchProducts가 호출되지 않으면 오래된 데이터) |
FetchProducts() | 스토어에 신선한 가격/가용성을 쿼리하고 캐시를 업데이트합니다 |
GetProductById(id) | ID로 단일 캐시된 제품을 반환합니다 |
이들은 서로 바꿔 쓸 수 없습니다. GetProducts()에 의존하기 전에 항상 먼저 FetchProducts()를 호출하십시오.
2단계 구매 흐름
IAP v5는 필수 2단계 흐름을 사용합니다: 보류(Pending) → 확인(Confirm).
store.PurchaseProduct(product)— 플랫폼 구매 다이얼로그를 시작합니다OnPurchasePending이 실행됩니다 —PendingOrder를 수신합니다- 영수증을 검증하고 플레이어에게 콘텐츠를 지급합니다
store.ConfirmPurchase(pendingOrder)— 트랜잭션을 확정합니다OnPurchaseConfirmed가 실행됩니다 —Order기본 유형을 수신하며, 패턴 매칭으로ConfirmedOrder(성공)와FailedOrder(확인 실패)를 구분합니다
콘텐츠를 지급한 후 반드시 ConfirmPurchase(pendingOrder)를 호출해야 합니다. 확인되지 않은 구매는 앱 재시작 시 재전송되어 구매 손실을 방지합니다.
중복 제거: OnPurchasePending은 동일한 구매에 대해 여러 번 실행될 수 있습니다 (예: 확인 전 앱 재시작). 이미 콘텐츠가 지급되었는지 항상 확인하십시오.
소모품: 확인된 소모품 구매는 FetchPurchases에서 반환되지 않습니다. 소모품 지급은 직접 추적하십시오 (예: Cloud Save 또는 Economy 사용).
지연된 구매: OnPurchaseDeferred는 Ask-to-Buy(iOS) 및 Google Play 지연 구매 시 실행됩니다. 콘텐츠를 지급하지 말고 — 승인 시 OnPurchasePending을 기다리십시오.
트랜잭션 복원
store.RestoreTransactions(callback)은 비소모품 및 구독 구매를 재전송합니다. 복원된 각 구매는 OnPurchasePending을 트리거합니다.
iOS에서 Apple App Store 규정 준수를 위해 필요합니다 — "구매 복원" 버튼을 추가하십시오.
Apple의 갱신되지 않는 구독은 RestoreTransactions를 통해 복원할 수 없습니다. 서버 측에서 추적하십시오.
영수증 검증
| 플랫폼 | 접근 방식 |
|---|---|
| Google Play | CrossPlatformValidator와 GooglePlayTangle.Data() — 로컬 검증 지원 |
| Apple (StoreKit 2) | 로컬 검증은 작동하지 않습니다. 서버 측 검증을 위해 order.Info.Apple?.jwsRepresentation을 사용하십시오 |
Unity 에디터의 Services > In-App Purchasing > Receipt Validation Obfuscator를 사용하여 탱글 데이터를 생성하십시오.
자격 확인
Order가 없고 특정 제품의 상태를 알고 싶을 때 사용합니다 (v4의 product.hasReceipt를 대체). 이미 Order가 있다면 유형을 확인하십시오: PendingOrder는 EntitledUntilConsumed (소모품) 또는 EntitledButNotFinished (비소모품/구독)에 매핑되고, ConfirmedOrder는 FullyEntitled에 매핑됩니다.
store.CheckEntitlement(product)를 호출하고 store.OnCheckEntitlement를 처리합니다. entitlement.Status == EntitlementStatus.FullyEntitled를 확인하십시오.
EntitlementStatus 값: FullyEntitled, EntitledUntilConsumed, EntitledButNotFinished, NotEntitled, Unknown.
기존 구매 가져오기
store.FetchPurchases()는 스토어에서 현재 구매를 모두 검색합니다. 앱 시작 시 유용합니다.
| 메서드 | 동작 |
|---|---|
GetPurchases() | 캐시된 구매 목록을 반환합니다 |
FetchPurchases() | 스토어에 현재 구매를 쿼리하고 캐시된 목록을 덮어씁니다 |
FetchPurchases()는 호출 시마다 전체 캐시 목록을 교체합니다. 비소모품 및 구독만 반환됩니다.