iOS 영수증 검증 (StoreKit 2)
Unity IAP 5.0 (StoreKit 2) 의 서명된 거래(Signed Transaction, 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?.jwsRepresentation | string |
| 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 등록 절차
| 단계 | 설명 |
|---|---|
| 1 | App Store Connect > 앱 선택 > 앱 정보 > App Store Server Notifications 로 이동 |
| 2 | Production Server URL 에 위 Webhook URL 을 입력 |
| 3 | Sandbox Server URL 에도 동일한 URL 을 입력 |
| 4 | Notification Version 은 "Version 2" 를 선택 후 저장 |
Webhook 수신 검증도 JWS 서명(Apple 인증서 체인)만으로 이루어지므로 별도의 인증 키가 필요하지 않습니다. Production / Sandbox 구분은 Apple이 전송하는 payload의 environment 필드로 자동 판별됩니다.