Dear PlayFab community,
I am having some trouble with validating a Sandbox iOS receipt using Unity IAP and iOS.
The iOS event that's triggered when attempting to validate is:
{ "EventName": "player_receipt_validation", "PaymentProvider": "iTunes Sandbox", "PaymentType": "ReceiptValidation", "ReceiptContent": "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", "Valid": false, "Error": "InvalidBundleID", "EntityId": "121BD68E8A8B5E87", "EventNamespace": "com.playfab", "EntityType": "player", "Source": "PlayFab", "TitleId": "44B1", "EventId": "9023c388355c4890891f48757e615f9a", "SourceType": "BackEnd", "Timestamp": "2018-07-25T03:30:51.9365555Z", "History": null, "CustomTags": null, "Reserved": null, "PlayFabEnvironment": { "Vertical": "master", "Cloud": "main", "Application": "mainserver", "Commit": "48e3b14" } }
Note specifically:
"Valid": false, "Error": "InvalidBundleID",
I have triple-checked that I'm using the correct BundleID in PlayFab, and that it corresponds to the ProductID for the IAP on iTunesConnect. My test user successfully completed the purchase on the device.
I am not having the same issues on Android with Google Play:
{ "EventName": "player_receipt_validation", "PaymentProvider": "Google Play", "PaymentType": "ReceiptValidation", "ReceiptContent": "{\"orderId\":\"GPA.3304-4256-7912-59329\",\"packageName\":\"net.digitalmonsoon.letterheroes\",\"productId\":\"net.digitalmonsoon.letterheroes.booster.major.06\",\"purchaseTime\":1532480733135,\"purchaseState\":0,\"developerPayload\":\"{\\\"developerPayload\\\":\\\"\\\",\\\"is_free_trial\\\":false,\\\"has_introductory_price_trial\\\":false,\\\"is_updated\\\":false}\",\"purchaseToken\":\"cmoabmmpapflonbmcnhpjkbl.AO-J1OxqWk_MIw64vgB_slbpOSP_rsjPp8B7yh4QZYJFCZJNCS59yJnX7149N0i17ShRf7I7PJXcfB3EQEMztZIERcMJwNtocfh41FGDJEWwBNRRcEr8N2llQjP4lP29BeIdR4xwKRwAGO5b8PYW5an3k8ysOBledFgWU9DxuFnKmoU53CRSqHgFnCtOACjS8pg4bnjeNrAe\"}", "Valid": true, "Error": null, "EntityId": "A4D08305FCAFFD7B", "EventNamespace": "com.playfab", "EntityType": "player", "Source": "PlayFab", "TitleId": "44B1", "EventId": "19a257e97dfa4bf5a996e0e415a67133", "SourceType": "BackEnd", "Timestamp": "2018-07-25T01:05:36.6257271Z", "History": null, "CustomTags": null, "Reserved": null, "PlayFabEnvironment": { "Vertical": "master", "Cloud": "main", "Application": "mainserver", "Commit": "48e3b14" } }
My C# code to manage the Unity IAP aspects is as follows:
Product product = args.purchasedProduct; // args is of type PurchaseEventArgs and is passed into the function. if ((product != null) && (product.hasReceipt)) { /* Get the embedded receipt data. Example of args.purchasedProduct.receipt: Apple Sandbox: {"Store":"AppleAppStore","TransactionID":"1000000377486512","Payload":"<SOME REALLY LONG UUENCODED STRING>"} Google Play Sandbox: (Raw string form.) {\"Store\":\"GooglePlay\",\"TransactionID\":\"GPA.3351-5231-4193-03133\",\"Payload\":\"{\\\"json\\\":\\\"{\\\\\\\"orderId\\\\\\\":\\\\\\\"GPA.3351-5231-4193-03133\\\\\\\",\\\\\\\"packageName\\\\\\\":\\\\\\\"net.digitalmonsoon.letterheroes\\\\\\\",\\\\\\\"productId\\\\\\\":\\\\\\\"net.digitalmonsoon.letterheroes.bundle.02\\\\\\\",\\\\\\\"purchaseTime\\\\\\\":1523490394536,\\\\\\\"purchaseState\\\\\\\":0,\\\\\\\"purchaseToken\\\\\\\":\\\\\\\"iahicnndbljhpjdeiemhjpma.AO-J1Ox-FveuvUV4KQxSm-nkXqOgyMnAHNaGtCYNOVQHGVO6up11XJU2ntUG814pA_Nz5bVESQCbxZ3S8tYrGZiSCjXd-sL ... */ PlayFab.Json.JsonObject receipt = Utility.MakeObjectFromJsonSimple(product.receipt); #if UNITY_IOS PlayFabClientAPI.ValidateIOSReceipt ( new ValidateIOSReceiptRequest { CurrencyCode = product.metadata.isoCurrencyCode, PurchasePrice = Decimal.ToInt32(product.metadata.localizedPrice * 100), ReceiptData = (string)(receipt["Payload"]) }, (ValidateIOSReceiptResult result) => #endif #if UNITY_ANDROID PlayFab.Json.JsonObject payload = Utility.MakeObjectFromJsonSimple((string)(receipt["Payload"])); PlayFabClientAPI.ValidateGooglePlayPurchase ( new ValidateGooglePlayPurchaseRequest { CurrencyCode = product.metadata.isoCurrencyCode, PurchasePrice = Decimal.ToUInt32(product.metadata.localizedPrice * 100), ReceiptJson = (string)(payload["json"]), Signature = (string)(payload["signature"]) }, (ValidateGooglePlayPurchaseResult result) => #endif ... }
I have successfully made purchases with iOS in sandbox mode before. As far as I know, this code hasn't changed since I was successful.
I'd appreciate any help anyone can provide!