본문으로 건너뛰기

iOS 영수증 검증 (StoreKit 2)

Unity IAP 5.0 (StoreKit 2) 의 서명된 거래(Signed Transaction, JWS)를 검증한다.

StoreKit 2 (JWS) 방식

이 메서드는 Unity IAP 5.0 (iOS 15.0 이상) 의 StoreKit 2 서명된 거래(JWS)를 검증합니다. Unity IAP 4.x (StoreKit 1) 의 Base64 영수증을 사용하는 경우 iOS 영수증 검증 을 참고하세요.

호출 정보

IAP.IOS_JWS(string jwsTransaction, string productID, PlayNANOODelegate callback) {}
IAP.IOS_JWS(string jwsTransaction, string productID, bool isDuplicateAllow, PlayNANOODelegate callback) {}

호출 상세 정보

파라미터설명타입
jwsTransaction서명된 거래 정보 (JWS). Unity IAP 5.0의 pendingOrder.Info.Apple?.jwsRepresentationstring
productID결제 상품 아이디string
isDuplicateAllow영수증 중복 검증 허용 여부boolean
callback통신 결과PlayNANOODelegate
화폐/금액 파라미터 불필요

레거시 IOS() 와 달리 currency, price 를 전달하지 않습니다. 통화·금액은 서버가 JWS payload 에서 직접 추출하여 위·변조를 방지합니다.

예제

유니티 IAP 서비스를 사용하는 경우 (Unity IAP 5.0)

using PlayNANOO;
using UnityEngine.Purchasing;

public class PlayNANOOExample : MonoBehaviour
{
Plugin plugin;

void Awake()
{
plugin = Plugin.GetInstance();
}

// Unity IAP 5.0 - PendingOrder 처리
public void OnPurchasePending(PendingOrder pendingOrder)
{
string jws = pendingOrder.Info.Apple?.jwsRepresentation;
string productID = pendingOrder.CartOrdered.Items()[0].Product.definition.id;

plugin.IAP.IOS_JWS(jws, productID, (status, errorMessage, jsonString, values) => {
if (status.Equals(Configure.PN_API_STATE_SUCCESS))
{
Debug.Log(values["UserID"]);
Debug.Log(values["PackageName"]);
Debug.Log(values["OrderID"]);
Debug.Log(values["ProductID"]);
Debug.Log(values["Currency"]);
Debug.Log(values["Quantity"]);
Debug.Log(values["Price"]);
Debug.Log(values["PurchaseState"]);

// 검증 성공 시 거래 확정
storeController.ConfirmPurchase(pendingOrder);
}
else
{
Debug.Log("Fail");
}
});
}
}

통신 결과

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"UserID" : "String",
"PackageName" : "String",
"OrderID" : "String",
"ProductID" : "String",
"Quantity" : "Integer",
"Currency" : "String",
"Price" : "Integer",
"PurchaseState" : "String"
}

통신 결과 상세 정보

데이터키설명타입
UserID사용자 식별 아이디string
PackageName앱 패키지명string
OrderID주문 아이디 (transactionId)string
ProductID결제 상품 아이디string
Quantity구매 수량integer
Currency결제 화폐 코드string
Price결제 상품 금액integer
PurchaseState검증 결과 (purchase 정상결제 / wait 처리 진행중 / cancel 검증실패)string
환불 감지

StoreKit 2 전환 게임은 App Store Server Notifications(Webhook)를 통해 환불을 자동으로 감지할 수 있습니다. 등록 절차는 이 페이지 하단의 환불 Webhook 등록 항목을 참고하세요.

에러 정보

영수증 검증에 실패한 경우 ErrorCode : 20000
ErrorMessage : ValidationFailException

어플리케이션 패키지명이 일치하지 않는 경우 ErrorCode : 20002
ErrorMessage : NotMatchPackageNameException

이미 사용된 영수증인 경우 ErrorCode : 20005
ErrorMessage : ExistsReceiptException

환불 Webhook 등록 (App Store Server Notifications)

환불(REFUND) 등의 이벤트를 실시간으로 수신하려면 App Store Server Notifications(Version 2)에 아래 Webhook URL을 등록합니다. Webhook은 게임(앱) 단위로 동작하므로 SDK 버전과 무관하게 URL만 등록하면 환불이 결제 로그에 자동 반영됩니다.

Webhook URL

https://service-api.playnanoo.com/webhook/apple/{gameId}

{gameId} 는 게임 채널 아이디입니다. 콘솔 > 설정 > API 및 플랫폼 설정 > iOS 하단에서 게임별로 자동 생성된 실제 URL을 복사 버튼으로 복사해 사용하세요.

App Store Connect 등록 절차

단계설명
1App Store Connect > 앱 선택 > 앱 정보 > App Store Server Notifications 로 이동
2Production Server URL 에 위 Webhook URL 을 입력
3Sandbox Server URL 에도 동일한 URL 을 입력
4Notification Version"Version 2" 를 선택 후 저장
별도 인증 키(.p8) 불필요

Webhook 수신 검증도 JWS 서명(Apple 인증서 체인)만으로 이루어지므로 별도의 인증 키가 필요하지 않습니다. Production / Sandbox 구분은 Apple이 전송하는 payload의 environment 필드로 자동 판별됩니다.