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!
Answer by John Peterson · Jul 25, 2018 at 04:30 AM
Bah...turned out the PlayFab Add-On for Apple was using an older "iOS App Bundle ID". I was thinking of BundleID as the in-game economy bundle for my purchase instead of the app itself. <blush>