Unity3D+PlayFab验证Google Play IAP收据失败求助
问题场景
Unity安卓手游中Google Play IAP购买流程正常完成,但调用PlayFab的ValidateGooglePlayPurchase接口时,返回错误:Invalid receipt(错误码1021,HTTP 400)。
验证代码
[System.Serializable] public class ReceiptWrapper { public string Store; public string Payload; } [System.Serializable] public class GooglePayloadWrapper { public string json; public string signature; } public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args) { int pearlAmount = GetPearlAmount(args.purchasedProduct.definition.id); Debug.Log($"JHL: Processing purchase for product: {args.purchasedProduct.definition.id}"); Debug.Log($"JHL: Raw receipt: {args.purchasedProduct.receipt}"); try { // Parse the outer receipt wrapper var wrapper = JsonUtility.FromJson<ReceiptWrapper>(args.purchasedProduct.receipt); Debug.Log($"JHL: Store: {wrapper.Store}"); Debug.Log($"JHL: Payload: {wrapper.Payload}"); if (Application.platform == RuntimePlatform.Android) { // Parse the Google Play specific payload var gpDetails = JsonUtility.FromJson<GooglePayloadWrapper>(wrapper.Payload); Debug.Log($"JHL: Google JSON: {gpDetails.json}"); Debug.Log($"JHL: Google Signature: {gpDetails.signature}"); // The json field is already a JSON string, don't parse it again var request = new ValidateGooglePlayPurchaseRequest { ReceiptJson = gpDetails.json, Signature = gpDetails.signature, CurrencyCode = args.purchasedProduct.metadata.isoCurrencyCode, PurchasePrice = (uint)(args.purchasedProduct.metadata.localizedPrice * 100) }; // Log the complete request for debugging Debug.Log($"JHL: Complete request being sent to PlayFab:"); Debug.Log($"JHL: ReceiptJson: {request.ReceiptJson}"); Debug.Log($"JHL: Signature: {request.Signature}"); Debug.Log($"JHL: CurrencyCode: {request.CurrencyCode}"); Debug.Log($"JHL: PurchasePrice: {request.PurchasePrice}"); PlayFabClientAPI.ValidateGooglePlayPurchase(request, result => { Debug.Log($"JHL: Purchase validation successful!"); Player.Instance.AddPearls(pearlAmount); UIFunctions.Instance.ShowMessage($"Purchase successful!\nAdded {pearlAmount} pearls"); }, error => { Debug.LogError($"JHL: Failed to validate purchase: {error.ErrorMessage}"); Debug.LogError($"JHL: Error details: {JsonUtility.ToJson(error)}"); Debug.LogError($"JHL: HTTP code: {error.HttpCode}"); Debug.LogError($"JHL: Error code: {error.Error}"); UIFunctions.Instance.ShowMessage("Purchase validation failed.\nPlease contact support."); }); } } catch (System.Exception e) { Debug.LogError($"JHL: Exception while processing receipt: {e}"); Debug.LogError($"JHL: Stack trace: {e.StackTrace}"); } return PurchaseProcessingResult.Complete; }
相关日志
Info Unity JHL: Processing purchase for product: com.pixelfish.pearl100 Info Unity IAPManager:ProcessPurchase(PurchaseEventArgs) Info Unity UnityEngine.Purchasing.PurchasingManager:ProcessPurchaseIfNew(Product) Info Unity UnityEngine.Purchasing.Extension.UnityUtil:Update() Info Unity JHL: Final Receipt JSON being sent: {"orderId":"GPA.3396-9471-9799-74081","packageName":"com.PufferfishStudios.PixelFish","productId":"com.pixelfish.pearl100","purchaseTime":1743075692104,"purchaseState":0,"purchaseToken":"doeklojbfffbgphcipbmflaa.AO-J1OzClvRrlk2HoHz343vYDytID4Cxjx2axF-r9-VcNgCIKtEk5q3gBqatb9DUQPubVGeAYT9dGgxSfJMLYwVCKw8QX2_Lw_3q4PVTRlutjLP0yoLcL8A","quantity":1,"acknowledged":false} Info Unity IAPManager:ProcessPurchase(PurchaseEventArgs) Info Unity UnityEngine.Purchasing.PurchasingManager:ProcessPurchaseIfNew(Product) Info Unity UnityEngine.Purchasing.Extension.UnityUtil:Update() Info Unity JHL: Final Signature being sent: jEBe5C6yXZfN/Ro36+FwtOeXFkhQcTvEHE7/TlJZkOVGfZxT6FKTNXrWqBG0f6Omi5+xz03RUoSN6rnQimM6ANCRe3IKwYfgRA9PkFUGjZ0Eo2c/5yRTlNLmuyEro9VkT/L7VOwl9Vxcvkg7/uQr+6SsAUhSJ7cd5cyKnX8DxvsgZN02zBa9ajOm/JzhyuMJDlNEmQ5YbtGpjxGj8hFiSy/yBrMskkkhSY+MCbUhU/yAvDcT0bOx/NCzqud7Nt5odkbZqKQ8OsPRRh/2sbXJ21oeRde2pASceQqHdeUhRe+O+MuAyWHwxdXmqUFpsDdYsxvudycLLqI9oXnX5Yyg6g== Info Unity IAPManager:ProcessPurchase(PurchaseEventArgs) Info Unity UnityEngine.Purchasing.PurchasingManager:ProcessPurchaseIfNew(Product) Info Unity UnityEngine.Purchasing.Extension.UnityUtil:Update() Info Unity JHL: Final Currency: GBP Info Unity IAPManager:ProcessPurchase(PurchaseEventArgs) Info Unity UnityEngine.Purchasing.PurchasingManager:ProcessPurchaseIfNew(Product) Info Unity UnityEngine.Purchasing.Extension.UnityUtil:Update() Info Unity JHL: Final Price: 99 Info Unity IAPManager:ProcessPurchase(PurchaseEventArgs) Info Unity UnityEngine.Purchasing.PurchasingManager:ProcessPurchaseIfNew(Product) Info Unity UnityEngine.Purchasing.Extension.UnityUtil:Update() Error Unity JHL: Failed to validate purchase: Invalid receipt Error Unity <>c:b__18_1(PlayFabError) Error Unity PlayFab.Internal.PlayFabUnityHttp:OnResponse(String, CallRequestContainer) Error Unity PlayFab.Internal.d__12:MoveNext() Error Unity UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr) Error Unity JHL: Error details: {"ApiEndpoint":"/Client/ValidateGooglePlayPurchase","HttpCode":400,"HttpStatus":"BadRequest","Error":1021,"ErrorMessage":"Invalid receipt"} Error Unity <>c:b__18_1(PlayFabError) Error Unity PlayFab.Internal.PlayFabUnityHttp:OnResponse(String, CallRequestContainer) Error Unity PlayFab.Internal.d__12:MoveNext() Error Unity UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr) Error Unity JHL: HTTP code: 400 Error Unity <>c:b__18_1(PlayFabError) Error Unity PlayFab.Internal.PlayFabUnityHttp:OnResponse(String, CallRequestContainer) Error Unity PlayFab.Internal.d__12:MoveNext() Error Unity UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr) Error Unity JHL: Error code: InvalidReceipt Error Unity <>c:b__18_1(PlayFabError) Error Unity PlayFab.Internal.PlayFabUnityHttp:OnResponse(String, CallRequestContainer) Error Unity PlayFab.Internal.d__12:MoveNext() Error Unity UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
排查步骤
核对PlayFab公钥配置
登录PlayFab后台,进入设置 > 变现 > Google Play,确保填入的RSA公钥和Google Play控制台中应用内结算页面的公钥完全一致,不要包含多余的空格或换行符。检查包名与产品ID一致性
日志中收据包名是com.PufferfishStudios.PixelFish,产品ID是com.pixelfish.pearl100,需确认:- Google Play控制台应用包名、PlayFab后台配置的包名完全匹配
- Google Play和PlayFab中配置的产品ID完全一致(Google Play产品ID区分大小写)
处理订单确认状态
日志显示acknowledged:false,虽然不是直接验证失败原因,但Google Play要求购买后必须调用acknowledgePurchase确认订单,未确认的订单可能引发后续问题。可在验证成功后添加确认逻辑:var product = args.purchasedProduct; if (product.definition.type is ProductType.Consumable or ProductType.NonConsumable) { var req = new GooglePlayAcknowledgePurchaseRequest(product.receipt); UnityPurchasing.Instance.GooglePlayStore.AcknowledgePurchase(req, success => Debug.Log("订单确认成功"), fail => Debug.LogError("订单确认失败:" + fail)); }确认收据与签名完整性
检查日志中Final Receipt JSON和Final Signature是否完整,无字符截断或修改,确保传递给PlayFab的参数和日志中一致。区分测试与生产环境
若使用Google Play测试账号,需确保PlayFab后台环境配置对应;正式环境必须使用发布版APK测试,测试账号无法在正式环境中生效。升级PlayFab SDK
确保使用最新版PlayFab Unity SDK,旧版本可能存在接口参数兼容问题,同时确认PurchasePrice(最小货币单位)和CurrencyCode(ISO标准代码)参数传递正确(日志中99对应0.99GBP、GBP代码均正确)。
内容的提问来源于stack exchange,提问作者Jonny Holmes

