영수증 확인을 통해 사용자가 구매하지 않은 콘텐츠에 액세스하지 못하게 합니다.
영수증 검증은 애플리케이션 콘텐츠가 배포되는 시점에 수행하는 것이 좋습니다.
중요: Unity IAP는 로컬 확인 메서드를 제공하지만 로컬 확인은 사기에 더 취약합니다. 가능한 경우 서버 측에서 민감한 트랜잭션을 확인하는 것이 베스트 프랙티스로 간주됩니다. 자세한 내용은 사기 방지에 대한 Apple 및 Android 문서를 참조하십시오.
사용자가 구매한 콘텐츠가 장치에 이미 존재하는 경우, 애플리케이션은 콘텐츠의 해지 여부만 결정하면 됩니다.
Unity IAP는 Google Play와 Apple 스토어를 통해 콘텐츠를 숨기고 영수증을 파싱할 수 있는 툴을 제공합니다.
영수증 검증은 알려진 암호화 키를 사용해 진행됩니다. 이 키는 애플리케이션의 암호화된 Google Play 공용 키나 Apple 루트 인증서입니다.
사용자가 이 키를 교체할 수 있다면 영수증 확인 과정을 무력화할 수 있으므로, 사용자가 키를 찾아 수정하기 어렵도록 해야 합니다.
Unity IAP는 애플리케이션에서 암호화 키를 난독 처리할 수 있는 툴을 제공합니다. 이 툴은 키를 난독 처리하여 사용자가 액세스하기 어렵게 만듭니다. Unity 메뉴 바에서 Window > Unity IAP > IAP Receipt Validation Obfuscator 로 가야 합니다.
이 창은 Unity IAP와 번들된 Apple 루트 인증서와 애플리케이션의 Google Play Developer Console’s Services & APIs 페이지에서의 Google Play 공용 키를 둘 다 암호화하여 AppleTangle 과 GooglePlayTangle 이라는 두 개의 다른 C# 파일에 저장합니다. 이 파일은 프로젝트에 추가되어 다음 섹션에서 사용하게 됩니다.
Apple 스토어만 타겟하는 경우에는 Google Play 공용 키를 제공할 필요가 없으며, 그 반대도 마찬가지입니다.
CrossPlatformValidator
클래스를 사용하여 Google Play와 Apple 스토어에서 확인을 수행할 수 있습니다.
클래스에 Google Play 공용 키나 Apple 루트 인증서를 제공해야 하며, 두 플랫폼에서 확인을 수행하려면 둘 다 제공해야 합니다.
CrossPlatformValidator
는 다음 두 개의 검사를 수행합니다.
이 검증기는 Google Play와 Apple 플랫폼에서 생성된 영수증만 확인할 수 있습니다. 다른 플랫폼에서 생성한 영수증이나 에디터에서 생성한 모의 영수증을 확인하면 IAPSecurityException 오류가 발생합니다.
비밀 키를 제공하지 않은 플랫폼의 영수증을 확인하려고 시도하면 MissingStoreSecretException 오류가 발생합니다.
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
bool validPurchase = true; // Presume valid for platforms with no R.V.
// Unity IAP's validation logic is only included on these platforms.
#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
// Prepare the validator with the secrets we prepared in the Editor
// obfuscation window.
var validator = new CrossPlatformValidator(GooglePlayTangle.Data(),
AppleTangle.Data(), Application.bundleIdentifier);
try {
// On Google Play, result has a single product ID.
// On Apple stores, receipts contain multiple products.
var result = validator.Validate(e.purchasedProduct.receipt);
// For informational purposes, we list the receipt(s)
Debug.Log("Receipt is valid. Contents:");
foreach (IPurchaseReceipt productReceipt in result) {
Debug.Log(productReceipt.productID);
Debug.Log(productReceipt.purchaseDate);
Debug.Log(productReceipt.transactionID);
}
} catch (IAPSecurityException) {
Debug.Log("Invalid receipt, not unlocking content");
validPurchase = false;
}
#endif
if (validPurchase) {
// Unlock the appropriate content here.
}
return PurchaseProcessingResult.Complete;
}
영수증의 유효성뿐만 아니라 해당 내용도 검사해야 합니다. 사용자가 구매를 하지 않고 콘텐츠에 액세스하는 흔한 방법 중 하나는 다른 제품이나 애플리케이션에서 영수증을 제공하는 것입니다. 영수증은 진품이고 확인 과정을 통과하기 때문에, CrossPlatformValidator 가 제품 ID를 파싱한 결과에 따라 판단을 내리도록 해야 합니다.
스토어마다 구매 영수증을 구성하는 필드가 다릅니다. 스토어별 필드에 액세스하려면 IPurchaseReceipt
를 두 개의 서브타입인 GooglePlayReceipt
과 AppleInAppPurchaseReceipt
에 적용하면 됩니다.
var result = validator.Validate(e.purchasedProduct.receipt);
Debug.Log("Receipt is valid. Contents:");
foreach (IPurchaseReceipt productReceipt in result) {
Debug.Log(productReceipt.productID);
Debug.Log(productReceipt.purchaseDate);
Debug.Log(productReceipt.transactionID);
GooglePlayReceipt google = productReceipt as GooglePlayReceipt;
if (null != google) {
// This is Google's Order ID.
// Note that it is null when testing in the sandbox
// because Google's sandbox does not provide Order IDs.
Debug.Log(google.transactionID);
Debug.Log(google.purchaseState);
Debug.Log(google.purchaseToken);
}
AppleInAppPurchaseReceipt apple = productReceipt as AppleInAppPurchaseReceipt;
if (null != apple) {
Debug.Log(apple.originalTransactionIdentifier);
Debug.Log(apple.subscriptionExpirationDate);
Debug.Log(apple.cancellationDate);
Debug.Log(apple.quantity);
}
}
AppleValidator
클래스를 사용하여 Apple 영수증 세부 정보를 추출할 수 있습니다. 이 클래스는 버전 7.0 이후의 iOS 앱 영수증에만 작동하며 그 이전 버전의 영수증에서는 작동하지 않습니다.
#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// Get a reference to IAppleConfiguration during IAP initialization.
var appleConfig = builder.Configure<IAppleConfiguration>();
var receiptData = System.Convert.FromBase64String(appleConfig.appReceipt);
AppleReceipt receipt = new AppleValidator(AppleTangle.Data()).Validate(receiptData);
Debug.Log(receipt.bundleID);
Debug.Log(receipt.receiptCreationDate);
foreach (AppleInAppPurchaseReceipt productReceipt in receipt.inAppPurchaseReceipts) {
Debug.Log(productReceipt.transactionIdentifier);
Debug.Log(productReceipt.productIdentifier);
}
#endif
AppleReceipt
타입은 Apple의 ASN1 영수증 포맷을 모델링합니다. 각각의 필드에 대한 자세한 내용은 Apple 문서를 참조하십시오.
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.