包含此页的版本:
不含此页的版本:
收据验证可帮助您防止用户访问他们尚未购买的内容。
最佳做法是在分发应用程序内容时验证收据。
重要提示:虽然 Unity IAP 提供了本地验证方法,但本地验证更容易受到欺诈。尽可能在服务器端验证敏感事务被认为是最佳实践。有关更多信息,请参阅 Apple 和 Android 关于防欺诈的文档。
如果用户购买的内容已存在于设备上,则应用程序只需决定是否解锁它。
Unity IAP 提供了一些工具来帮助您隐藏内容,并通过 Google Play 和 Apple 商店验证和解析收据。
使用已知的加密密钥执行收据验证。对于您的应用程序,这是一个加密的 Google Play 公钥和/或 Apple 的根证书。
如果用户可以替换这些密钥,他们可能会失败您的收据验证检查,因此让用户难以轻松找到和修改这些密钥非常重要。
Unity IAP 提供了一个工具,可以帮助您混淆应用程序中的加密密钥。这会混淆或混乱密钥,使用户更难访问它们。在 Unity 菜单栏中,转到窗口 > Unity IAPUnity In App Purchase
的缩写 见术语表 > IAP 收据验证混淆器。
此窗口将 Apple 的根证书(与 Unity IAP 捆绑在一起)和您的 Google Play 公钥(来自应用程序的 Google Play 开发者控制台的“服务和 API”页面)编码为两个不同的 C# 文件:AppleTangle 和 GooglePlayTangle。这些将添加到您的项目中,以便在下一节中使用。
请注意,如果您仅针对 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 应用收据,不适用于 Apple 已弃用的交易收据。
#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
这AppleReceipttype 模型 Apple 的 ASN1 收据格式。有关其字段的说明,请参阅 Apple 的文档。