We have recently done some upgrading:
Unity 2018.4.24.f1 → 2020.3.0f1
In App Purchasing 2.1.0 → 2.2.2
The problem that we are seeing is that when Android mobile devices are set to either the French or Swedish language we are seeing an exception that causing the initialization of UnityPurchasing to never return. We are calling UnityPurchasing.Initialize, but neither OnInitialized nor OnInitializedFailed is ever called. This is the exception that we are getting in the logs:
04-16 01:12:43.675 23551 23670 E Unity : FormatException: Input string was not in a correct format.
04-16 01:12:43.675 23551 23670 E Unity : at System.Number.StringToNumber (System.String str, System.Globalization.NumberStyles options, System.Number+NumberBuffer& number, System.Globalization.NumberFormatInfo info, System.Boolean parseDecimal) [0x00000] in <00000000000000000000000000000000>:0
04-16 01:12:43.675 23551 23670 E Unity : at System.Number.ParseDecimal (System.String value, System.Globalization.NumberStyles options, System.Globalization.NumberFormatInfo numfmt) [0x00000] in <00000000000000000000000000000000>:0
04-16 01:12:43.675 23551 23670 E Unity : at UnityEngine.Purchasing.JSONSerializer.DeserializeMetadata (System.Collections.Generic.Dictionary`2[TKey,TValue] data) [0x00000] in <00000000000000000000000000000000>:0
04-16 01:12:43.675 23551 23670 E Unity : at UnityEngine.Purchasing.JSONSerializer.DeserializeProductDescriptions (System.String json) [0x00000] in <00000000000000000000000000000000>:0
04-16 01:12:43.675 23551 23670 E Unity : at UnityEngine.Purchasing.NativeJSONStore.OnProductsRetrieved (System.String json) [0x00000] in <00000000000000000000000000000000>:0
04-16 01:12:43.675 23551 23670 E Unity : at System.Action.Invoke () [0x00000] in <00000000000000
It doesn’t seem to matter if we add all our products or just one, it never triggers the callback. If we don’t add any products or add an invalid IAP code to the builder then it successfully calls OnInitializationFailed with a
NoProductsAvailable failure reason. We have also tried reverting Unity IAP to version 2.1.0 that we were on previously, but we are getting the same result.
I doubt this matters, but small note our iap codes have decimal points in them (e.g. iap.product.2)
I’m out of ideas for what else to try so any help is greatly appreciated. Thanks in advance.
@jrucktenwald Can you try a test product without the dots like “gold50”? I doubt that is the issue, but something to rule out. We will check the locales you mention also.
@JeffDUnity3D Thanks for the response. This morning I added a dummy test product to our Google Play console “testproduct8” and only added that product to the ConfigurationBuilder, but received the same result of no response from the UnityPurchasing.Initialize() with the same error log as found in the original post.
HI @JeffDUnity3D just following up here on behalf of jrucktenwald on the above. We’re in a bit of a bind here so any info is greatly appreciated. Thank you for all the support!
Once we are able to test, we will schedule it into a future release. I might expect 3-4 weeks minimum, to properly set expectations. Are you able to test with the latest version of IAP 3.0.2?
Hey @JeffDUnity3D so we have tried to update to 3.0.2, but without changing any other client or server code our Apple sandbox account test purchases are no longer getting recognized as sandbox purchases. Apple’s verification endpoint is no longer returning a 21007 which it has always done. Instead we’re getting back a 21002, which means that it thinks the data is malformed.
I’m currently trying to track down how the PurchaseEventArgs from the IStoreListener ProcessPurchase are different in 3.0.2 than they were in 2.1.0. I haven’t seen any documentation about needing to make changes here, but if you know of any that would be greatly appreciated.
It’s working here for me. Can you elaborate “no longer getting recognized”, you mean you are charged actual $? What if you create another Sandbox account?
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
{
UnityPurchaseReceipt purchaseReceipt = LitJson.JsonMapper.ToObject<UnityPurchaseReceipt>(args.purchasedProduct.receipt);
var data = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(purchaseReceipt.Payload));
// send data to our server for server-side validation
}
This is basically how we’re getting the payload and passing it along to our server. Then our server takes the data field and sends it along to https://buy.itunes.apple.com/verifyReceipt
Before the upgrade this endpoint would return a response with a status of 21007 indicating that it was a purchase from a sandbox/test environment, which would then prompt us to call the https://sandbox.itunes.apple.com/verifyReceipt version of the endpoint. Now status 21007 is no longer returned, it’s returning a 21002 status from the first endpoint which according to apple indicates “The data in the receipt-data property was malformed or the service experienced a temporary issue”.
So I was trying to track down what the difference is between the purchaseReceipt.Payload between the different versions.
EDIT: Just wanted to add that this is happening for all our sandbox accounts.
So here are some results that I got from testing today.
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
{
Debug.Log($"args.purchasedProduct.receipt={args.purchasedProduct.receipt}");
}
On our iOS builds here are the print statements that we are getting with the different IAP versions. I have added .... where I trimmed out the long tokens and I added the ‘xxxx’ in the TransactionIDs. I’m not sure where it’s coming from at this point, but it looks like the Payload strings are different between the 2 versions. Maybe it’s an initialization setting that we need? Or the reason that we were getting the JSON string back was because we had something that was hanging onto an old version that got wiped out when we upgraded? Either way, any information that you might have for us is much appreciated.
Your 2.2.2 receipt format looks like iOS6 format. The 2.2.2 listing suggests it contains JSON-text, NOT base64 encoded JSON. Have you modified your local copy of UnityPurchasing.m. As mentioned, we already base64 encode the Payload unconditionally. You are calling LitJson.JsonMapper (not familiar with that component) followed by Convert.ToBase64String. We are not planning any changes at this time.
To the best of my knowledge UnityPurchasing.m wasn’t modified but there were a number of developers that are no longer with us that may have had a hand in it. I will look deeper into that possibility.
Something like that is what I was afraid of when I said “maybe the reason that we were getting the JSON string back was because we had something that was hanging onto an old version that got wiped out when we upgraded” in my previous post. I appreciate you following up and I will report back when I have any other information. Thanks.
Yeah sorry, I wasn’t completely clear. I was referring to something that was forcing us to be getting back and old version of the receipt data from the PurchaseEventArgs. At the time I didn’t realize that was an iOS6 version of the receipt data, but that sheds much more light onto the situation.
Well, once you pointed that out it didn’t take too long to locate the issue. I have verified that one of our developers did in fact modify the UnityPurchasing.m file. Your help and patience has been greatly appreciated. We will now be diligently working towards getting this resolved and updated to be using the proper receipt formatting. Thank you again.