본문으로 건너뛰기

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 필드로 자동 판별됩니다.