안드로이드 영수증 검증
안드로이드 인앱 결제(IAP) 영수증을 검증하는 API입니다.
URL 확인
이 API는 service-api.playnanoo.com 도메인을 사용합니다.
API 정보
- URL:
https://service-api.playnanoo.com/iap/v20221001/unity/android - Method:
PUT - 인증 필요: 예
DeviceInfo 상속
이 API의 Req 클래스는 DeviceInfo를 상속받습니다. DeviceInfo의 모든 속성이 자동으로 포함됩니다.
요청 파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| receipt | string | 필수 | 영수증 정보 |
| skuDetails | string | 필수 | 안드로이드 상품 정보 |
| signature | string | 필수 | 안드로이드 Signature |
| duplicate_allow | string | 필수 | 영수증 중복 검증 허용 여부 (Y/N) |
응답 데이터
Res 클래스
| 필드 | 타입 | 설명 |
|---|---|---|
| UserID | string | 사용자 ID |
| PackageName | string | 패키지 이름 |
| OrderID | string | 주문 ID |
| ProductID | string | 상품 ID |
| Currency | string | 통화 코드 |
| Quantity | string | 수량 |
| Price | string | 가격 |
| PurchaseState | string | 검증 결과purchase : 정상결제wait : 처리 진행중cancel : 검증실패 |
wait 상태 처리
wait 상태일 경우 재검증 요청을 보내주시면 됩니다.
Unity C# 구현
BaseResponse 클래스
모든 API 응답의 기본 클래스입니다.
public class BaseResponse
{
public string ErrorCode;
public string Message;
public string WithdrawalKey;
public string BlockKey;
}
필드 설명:
ErrorCode: 에러 코드Message: 에러 메시지WithdrawalKey: 탈퇴 유예 상태인 경우 복구에 필요한 키 (탈퇴 유예 중인 계정만 제공)BlockKey: 차단된 계정인 경우 제공되는 키 (차단된 계정만 제공)
안드로이드 IAP 검증 클래스
using System;
using System.Collections;
using UnityEngine.Networking;
public class IAPUnityAndroid
{
static string path = "https://service-api.playnanoo.com/iap/v20221001/unity/android";
[Serializable]
public class Req : DeviceInfo
{
//필수
public string receipt; // 영수증 정보
//옵션
public string skuDetails; // 안드로이드 상품 정보
//옵션
public string signature; // 안드로이드 Signature
//필수
public string duplicate_allow; // 영수증 중복 검증 허용 여부
public IEnumerator Send(string receipt, string skuDetails, string signature, bool isDuplicateAllow, Action<Res> onSuccess, Action<BaseResponse> onError)
{
if (!string.IsNullOrEmpty(receipt)) this.receipt = receipt;
if (!string.IsNullOrEmpty(skuDetails)) this.skuDetails = skuDetails;
if (!string.IsNullOrEmpty(signature)) this.signature = signature;
this.duplicate_allow = isDuplicateAllow ? "Y" : "N";
yield return HttpClient.Send<Req, Res>(
UnityWebRequest.kHttpVerbPUT,
path,
requireToken: true,
body: this,
onSuccess: onSuccess,
onError: onError
);
}
}
[Serializable]
public class Res : BaseResponse
{
public string UserID;
public string PackageName;
public string OrderID;
public string ProductID;
public string Currency;
public string Quantity;
public string Price;
public string PurchaseState;
}
}
사용 예제
public void ValidateAndroidIAP()
{
IAPUnityAndroid.Req req = new IAPUnityAndroid.Req();
// Google Play 결제 정보
string receipt = "{\"orderId\":\"GPA.1234-5678-9012-34567\",\"packageName\":\"com.example.game\",\"productId\":\"gold_100\",\"purchaseTime\":1234567890,\"purchaseState\":0,\"purchaseToken\":\"abcdefghijklmnop\"}";
string skuDetails = "{\"productId\":\"gold_100\",\"type\":\"inapp\",\"price\":\"$0.99\",\"price_amount_micros\":990000,\"price_currency_code\":\"USD\",\"title\":\"100 Gold\",\"description\":\"Get 100 gold coins\"}";
string signature = "Base64EncodedSignature==";
StartCoroutine(req.Send(
receipt: receipt,
skuDetails: skuDetails,
signature: signature,
isDuplicateAllow: false, // 중복 영수증 허용 안 함
onSuccess: res =>
{
switch (res.PurchaseState)
{
case "purchase":
// 정상 결제 - 아이템 지급
Debug.Log($"결제 완료: {res.ProductID}");
GiveItemToPlayer(res.ProductID, int.Parse(res.Quantity));
break;
case "wait":
// 처리 진행중 - 재검증 필요
Debug.Log("결제 처리 중입니다. 잠시 후 재검증을 요청합니다.");
StartCoroutine(RetryValidation(receipt, skuDetails, signature));
break;
case "cancel":
// 검증 실패
Debug.LogError("영수증 검증에 실패했습니다.");
break;
}
},
onError: (error) =>
{
Debug.LogError($"IAP 검증 실패: [{error.ErrorCode}] [{error.Message}]");
}
));
}
private void GiveItemToPlayer(string productId, int quantity)
{
// 실제 아이템 지급 로직 구현
Debug.Log($"아이템 지급: {productId} x {quantity}");
}
private IEnumerator RetryValidation(string receipt, string skuDetails, string signature)
{
yield return new WaitForSeconds(3f); // 3초 후 재시도
ValidateAndroidIAP(); // 재검증 호출
}
영수증 중복 검증
isDuplicateAllow를 false로 설정하면 동일한 영수증으로 중복 검증이 불가능합니다. 테스트 환경에서는 true로 설정하여 중복 검증을 허용할 수 있습니다.
Google Play 영수증
receipt는 Google Play Billing Library에서 제공하는 purchaseToken을 포함한 JSON 형식의 영수증 정보입니다.
Unity IAP 사용 예제
Unity IAP를 사용하는 경우 ProcessPurchase 콜백에서 영수증 검증을 수행할 수 있습니다.
using UnityEngine.Purchasing;
public class IAPManager : IStoreListener
{
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
{
// 안드로이드 플랫폼 체크
if (Application.platform == RuntimePlatform.Android)
{
// 플레이나누 영수증 검증 API 호출
IAPUnityAndroid.Req req = new IAPUnityAndroid.Req();
StartCoroutine(req.Send(
receipt: args.purchasedProduct.receipt, // Unity IAP 영수증 전체
skuDetails: "", // Unity IAP 사용 시 선택사항
signature: "", // Unity IAP 사용 시 선택사항
isDuplicateAllow: false,
onSuccess: res =>
{
switch (res.PurchaseState)
{
case "purchase":
// 정상 결제 - 아이템 지급
Debug.Log($"영수증 검증 성공: {res.ProductID}");
GiveItemToPlayer(res.ProductID, int.Parse(res.Quantity));
break;
case "wait":
// 처리 진행중 - 재검증 필요
Debug.Log("결제 처리 중입니다. 잠시 후 재검증을 요청합니다.");
break;
case "cancel":
// 검증 실패
Debug.LogError("영수증 검증에 실패했습니다.");
break;
}
},
onError: error =>
{
Debug.LogError($"영수증 검증 실패: [{error.ErrorCode}] {error.Message}");
}
));
// 비동기 검증이 완료될 때까지 보류
return PurchaseProcessingResult.Pending;
}
return PurchaseProcessingResult.Complete;
}
private void GiveItemToPlayer(string productId, int quantity)
{
// 실제 아이템 지급 로직 구현
Debug.Log($"아이템 지급: {productId} x {quantity}");
}
// IStoreListener 나머지 메서드들
public void OnInitialized(IStoreController controller, IExtensionProvider extensions) { }
public void OnInitializeFailed(InitializationFailureReason error) { }
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason) { }
}
비동기 처리 주의
ProcessPurchase 메서드는 동기 메서드이지만, 영수증 검증은 비동기로 처리됩니다. 검증이 완료될 때까지 PurchaseProcessingResult.Pending을 반환하고, 검증 완료 후 IStoreController.ConfirmPendingPurchase()를 호출하여 구매를 완료 처리해야 합니다.
재시도 로직
영수증 검증 실패 시 PurchaseProcessingResult.Pending을 반환하면 Unity IAP가 다음 앱 실행 시 자동으로 재시도합니다. 네트워크 오류 등 일시적인 문제에 대비할 수 있습니다.