영수증 확인을 통해 사용자가 구매하지 않은 콘텐츠에 액세스하지 못하게 합니다.
영수증 검증은 애플리케이션 콘텐츠가 배포되는 시점에 수행하는 것이 좋습니다.
중요: 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 문서를 참조하십시오.