In app purchase using Corona library fails

Hello,

In one of my apps I have a non-consumable purchase that has worked fine since I published the app last December. But now it suddenly doesn’t work even though it is still the same version in the AppStore. I have tried on several iPhones (installing/uninstalling) and it works on some of them (both 10.3.2 and 10.2.1) but not all. I am using IAP Badger plugin from the Corona Marketplace but according to “Happy Mongoose Games” (who made the plugin), IAP Badger is just a lua wrapper class for Corona’s store libraries and doesn’t handle the detail of interactions with iTunes Connect etc. Below you have:

A. The logs from a device where the failure occurs
B. My original question to Apple support
C. The Answer from Apple support

Any suggestions as to the cause of this error?


A. The logs from a device where the failure occurs
Jun 21 20:42:52 IRD4 itunesstored(iTunesStore)[116] <Notice>: ISDevice: Taking power assertion: com.apple.itunesstored.purchase
Jun 21 20:42:52 IRD4 accountsd(AccountsDaemon)[88] <Notice>: “<private> (<private>) received”
Jun 21 20:42:52 IRD4 itunesstored(Accounts)[116] <Notice>: “The connection to ACDAccountStore was invalidated.”
Jun 21 20:42:52 IRD4 itunesstored(iTunesStore)[116] <Notice>: ISStoreURLOperation: Started request at [519763372.33] for <private>
Jun 21 20:42:52 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC TCP Conn Start [486:0x1091b9b30]
Jun 21 20:42:52 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC TCP Conn Event [486:0x1091b9b30]: 1 Err(0)
Jun 21 20:42:52 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC TCP Conn Connected [486:0x1091b9b30]: Err(0)
Jun 21 20:42:52 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC Enabling TLS [486:0x1091b9b30]
Jun 21 20:42:52 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC TLS Event [486:0x1091b9b30]: 2, Pending(0)
Jun 21 20:42:52 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC TLS Event [486:0x1091b9b30]: 11, Pending(0)
Jun 21 20:42:52 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC TLS Event [486:0x1091b9b30]: 14, Pending(0)
Jun 21 20:42:52 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC TLS Trust Result [486:0x1091b9b30]: 0
Jun 21 20:42:53 IRD4 CommCenter(libATCommandStudioDynamic.dylib)[74] <Notice>: QMI: Svc=0x02(DMS) Req MsgId=0x002f Bin=[<private>]
Jun 21 20:42:53 IRD4 CommCenter(libATCommandStudioDynamic.dylib)[74] <Notice>: QMI: Svc=0x02(DMS) Resp MsgId=0x002f Bin=[<private>]
Jun 21 20:42:53 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC TLS Event [486:0x1091b9b30]: 20, Pending(0)
Jun 21 20:42:53 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC TCP Conn Event [486:0x1091b9b30]: 8 Err(0)
Jun 21 20:42:53 IRD4 itunesstored(CFNetwork)[116] <Notice>: TIC TLS Handshake Complete [486:0x1091b9b30]
Jun 21 20:42:53 IRD4 itunesstored(iTunesStore)[116] <Notice>: ISStoreURLOperation: Received 200 response: [0.93s] <private>
Jun 21 20:42:53 IRD4 itunesstored(iTunesStore)[116] <Notice>: ISStoreURLOperation: Finished loading: [519763373.27, 0.94s] <private>
Jun 21 20:42:53 IRD4 itunesstored[116] <Notice>: PurchaseProtocolDataProvider: Error handler resolved with type: 0
Jun 21 20:42:53 IRD4 itunesstored[116] <Notice>: PurchaseOperation: Purchase failed with code <private>: <private>
Jun 21 20:42:53 IRD4 itunesstored[116] <Notice>: PurchaseOperation: storeCorrelationID: <private>
Jun 21 20:42:53 IRD4 itunesstored(iTunesStore)[116] <Notice>: ISDevice: Releasing power assertion: com.apple.itunesstored.purchase
Jun 21 20:42:53 IRD4 itunesstored[116] <Notice>: [AppReceipt] No receipt data for: <private>
Jun 21 20:42:53 IRD4 itunesstored[116] <Notice>: StoreKitClient: Buy failed with error: <private> for payment: <private>

B. My original question to Apple support
In my app, I have a non-consumable purchase that has worked fine since I published the app last December but now it does not work since I updated my iPhone 6S to 10.3.2. I have tried on several iPhones and it works on some of them (both 10.3.2 and 10.2.1) but not all. I googled the error but the only thing I could find that it may have something to do with the “iOS Trusted Root Certificate”. Please note that I have not changed anything in the app since the time it worked on all devices, the version is still the same.

C. The Answer from Apple support (edited)
The issue sounds like one where the application statically validates the applicationReceipt to determine whether the user has purchased the non-consumable subscription. Does the app do this. Furtheremore, does the app link to it’s own copy of the Apple Trusted Root Certificate? If so, my guess is that this problem is not iOS dependent, but for whatever reason, the app did not get reinstalled from the iTunes Store since last October until you installed (updated) to iOS 10.2. Late last year, the Apple Trusted Certificate used by the iTunes Store to sign applicationReceipts - expired. A new certificate was obtained, and used to sign applicationReceipts. If you never re-installed the app for quite a while, the original applicationReceipt would have remained in the app, and the earlier code would have been able to statically validate the receipt. However at some point, I’m guessing, you reinstalled the app from the App Store, In doing so, the applicationReceipt is now one which is signed with the new certificate - however, it no longer matches the copy in your code, and the app fails to validate the non-renewing subscriptions.

I’m asking our engineers to take a look at this. It sounds like something that they may have more experience with than I do. 

@Rob:

Great, thanks! :slight_smile:

I just heard from the Apple support guy, who asked me to provide exact details about how the request is made from Corona. If your engineers don’t find anything “on your end” perhaps you could give me some details about how Corona handles these things so that I can give him the info he needs to analyze the issue.

@Rob:

Please see the attached file with the conversation between Apple support and me. They have basically given up on solving this… Any news on this from your engineers?

Hi @Divergent Monkey. 

After reading the discussion with Apple, I have a few questions.

Do you have one app or two apps?  It seems that there is quickball and numerizer. It also sounds like numerizer is trying to use a product ID belonging to quickball. Or did you some how manage to use the same ID in both apps?  Apple generally wants these to be unique and I’m surprised that iTunes Connect isn’t enforcing this.  Are you seeing the problem with one app or both?

I also see that it appears to only happen to your testing devices. Have you make sure to completely have logged out from any testing accounts? Are you using a version downloaded from the live app store?

Are other people reporting the issue?

Can you provide the link to your app?

Are you calling store.loadProducts() in  your code?

Thanks

Rob

Hello Rob,

I have two apps, Numerizer (the one with the issues) and Quirkball. I have checked and I do not use the same AppStore Id in both apps. What’s really strange is that it works on some devices but not on others. I have tried on several iPhones and it works on some of them (both 10.3.2 and 10.2.1) but not all even though they are using the same AppStore version of the app. The other app, Quirkball, works on all devices.

Attached, you have my iap code in full. I do not use store.loadProducts but again, it works on some devices so the product name hard coded cannot be wrong (which I have also checked). However, I will implement store.loadProducts in my code and see if it makes any difference.

Here is the link to the app on AppStore:

https://itunes.apple.com/us/app/numerizer/id1136832685?mt=8

I don’t know if this is good news or bad news, but your app failed to purchase on both my iPad 4 (10.3.2) and iPhone 6 (10.3.3). I immediately got a Purchase Failed dialog. 

Are you generating a native.systemDialog() when you get a fail? I’m curious if it’s coming from you, IAP_Badger or the system.

This seems like it might be the start of the problem:

Aug 6 12:38:15 Robs-iPad accountsd(AccountsDaemon)[2742] \<Notice\>: "\<private\> (\<private\>) received" Aug 6 12:38:15 Robs-iPad itunesstored(iTunesStore)[4096] \<Error\>: Could not load library [21] Aug 6 12:38:15 Robs-iPad itunesstored(Accounts)[4096] \<Notice\>: "The connection to ACDAccountStore was invalidated." Aug 6 12:38:15 Robs-iPad itunesstored(iTunesStore)[4096] \<Error\>: Could not load library [21]

In Googling around for this, there was very little in the way of hits. A Unity forum post with no responses, this post and on the Apple Developer forums dating back to iOS 9 (but had people complaining about it as recent as this past March).  The consensus in that thread suggested it was a credit card problem where iTunes would generate a fail because the CC data was invalid but would take you to the payment page to let you update it and when it sent you back you only got a partial receipt. But that’s not the case here. I was able to make a normal purchase in the store from my phone. I got prompted for my touch ID like I expected. I don’t even get the touchID with your app.

My son tried on his 6 plus and also got the failure.

I know none of this helps get the problem solved. I’m going to keep digging and check in with Engineering.  Do you get this if you use TestFlight with an unpublished app hitting the sandbox?

Rob

Hello Rob,

In a way, it’s good news since it at least someone else is experiencing the same problem, which means I’m not crazy…

As you can see in the code that I attached to my last post, I call native.showAlert() to communicate success or failure when purchasing or restoring. I have the following messages at failure:

 native.showAlert("Error", "Purchase failed.", { "OK" }, onConfirmAlert) native.showAlert("Error", "Could not restore purchase.", { "OK" }, onConfirmAlert)

Depending on the exact message that you got, it could come either from my code, IAP Badger or the system.

FYI: I have been in contact with the people at Happy Mongoose Games (creators of IAP Badger) about this and another issue that could possibly be related to this: if I call iap.loadProduct() without a callback listener, then iap.getLoadProductsFinished() always returns false. To this end, they have added verboseDebugOutput=true to the table you pass to your iap.init function as a help to see what happens behind the curtain. Unfortunately, no debug output whatsoever was generated when iap.getLoadProductsFinished() fails. I’m awaiting their response to this.

Engineering suggested that maybe you regenerate your provisioning profiles and make sure IAP is checked for them. Make sure the Bundle ID is right. I’m updating one of my apps that has IAP in it tonight, so I’ll have something I can test against and see if I have the same issue on my phone, but it sounds like something local to this specific app.

Rob

Hello,

Using loadProducts() seems to have helped and it now works on the same devices where it did not work before. Once I get it submitted to the AppStore, maybe you could try again to see if it works on your devices as well.

The other issue that I wrote about (iap.getLoadProductsFinished() always returning false when not calling loadProducts() with a listener) seems only to occur in the simulator. On a real device it works fine. I have an ongoing mail discussion with Happy Mongoose Game about that if you are interested.

@Rob:

I have now submitted a new version of Numerizer to both AppStore and GooglePlay. As far as I can tell, the issue is now resolved, but I would like to ask you to test it on the devices where it did not work for you before. Please let me know if the issue still persists on those devices.

Also, the problems with getLoadProductsFinished() in the simulator was a bug in IAP Badger but has now been fixed by Happy Mongoose Games.

I’m asking our engineers to take a look at this. It sounds like something that they may have more experience with than I do. 

@Rob:

Great, thanks! :slight_smile:

I just heard from the Apple support guy, who asked me to provide exact details about how the request is made from Corona. If your engineers don’t find anything “on your end” perhaps you could give me some details about how Corona handles these things so that I can give him the info he needs to analyze the issue.

@Rob:

Please see the attached file with the conversation between Apple support and me. They have basically given up on solving this… Any news on this from your engineers?

Hi @Divergent Monkey. 

After reading the discussion with Apple, I have a few questions.

Do you have one app or two apps?  It seems that there is quickball and numerizer. It also sounds like numerizer is trying to use a product ID belonging to quickball. Or did you some how manage to use the same ID in both apps?  Apple generally wants these to be unique and I’m surprised that iTunes Connect isn’t enforcing this.  Are you seeing the problem with one app or both?

I also see that it appears to only happen to your testing devices. Have you make sure to completely have logged out from any testing accounts? Are you using a version downloaded from the live app store?

Are other people reporting the issue?

Can you provide the link to your app?

Are you calling store.loadProducts() in  your code?

Thanks

Rob

Hello Rob,

I have two apps, Numerizer (the one with the issues) and Quirkball. I have checked and I do not use the same AppStore Id in both apps. What’s really strange is that it works on some devices but not on others. I have tried on several iPhones and it works on some of them (both 10.3.2 and 10.2.1) but not all even though they are using the same AppStore version of the app. The other app, Quirkball, works on all devices.

Attached, you have my iap code in full. I do not use store.loadProducts but again, it works on some devices so the product name hard coded cannot be wrong (which I have also checked). However, I will implement store.loadProducts in my code and see if it makes any difference.

Here is the link to the app on AppStore:

https://itunes.apple.com/us/app/numerizer/id1136832685?mt=8

I don’t know if this is good news or bad news, but your app failed to purchase on both my iPad 4 (10.3.2) and iPhone 6 (10.3.3). I immediately got a Purchase Failed dialog. 

Are you generating a native.systemDialog() when you get a fail? I’m curious if it’s coming from you, IAP_Badger or the system.

This seems like it might be the start of the problem:

Aug 6 12:38:15 Robs-iPad accountsd(AccountsDaemon)[2742] \<Notice\>: "\<private\> (\<private\>) received" Aug 6 12:38:15 Robs-iPad itunesstored(iTunesStore)[4096] \<Error\>: Could not load library [21] Aug 6 12:38:15 Robs-iPad itunesstored(Accounts)[4096] \<Notice\>: "The connection to ACDAccountStore was invalidated." Aug 6 12:38:15 Robs-iPad itunesstored(iTunesStore)[4096] \<Error\>: Could not load library [21]

In Googling around for this, there was very little in the way of hits. A Unity forum post with no responses, this post and on the Apple Developer forums dating back to iOS 9 (but had people complaining about it as recent as this past March).  The consensus in that thread suggested it was a credit card problem where iTunes would generate a fail because the CC data was invalid but would take you to the payment page to let you update it and when it sent you back you only got a partial receipt. But that’s not the case here. I was able to make a normal purchase in the store from my phone. I got prompted for my touch ID like I expected. I don’t even get the touchID with your app.

My son tried on his 6 plus and also got the failure.

I know none of this helps get the problem solved. I’m going to keep digging and check in with Engineering.  Do you get this if you use TestFlight with an unpublished app hitting the sandbox?

Rob

Hello Rob,

In a way, it’s good news since it at least someone else is experiencing the same problem, which means I’m not crazy…

As you can see in the code that I attached to my last post, I call native.showAlert() to communicate success or failure when purchasing or restoring. I have the following messages at failure:

 native.showAlert("Error", "Purchase failed.", { "OK" }, onConfirmAlert) native.showAlert("Error", "Could not restore purchase.", { "OK" }, onConfirmAlert)

Depending on the exact message that you got, it could come either from my code, IAP Badger or the system.

FYI: I have been in contact with the people at Happy Mongoose Games (creators of IAP Badger) about this and another issue that could possibly be related to this: if I call iap.loadProduct() without a callback listener, then iap.getLoadProductsFinished() always returns false. To this end, they have added verboseDebugOutput=true to the table you pass to your iap.init function as a help to see what happens behind the curtain. Unfortunately, no debug output whatsoever was generated when iap.getLoadProductsFinished() fails. I’m awaiting their response to this.

Engineering suggested that maybe you regenerate your provisioning profiles and make sure IAP is checked for them. Make sure the Bundle ID is right. I’m updating one of my apps that has IAP in it tonight, so I’ll have something I can test against and see if I have the same issue on my phone, but it sounds like something local to this specific app.

Rob

Hello,

Using loadProducts() seems to have helped and it now works on the same devices where it did not work before. Once I get it submitted to the AppStore, maybe you could try again to see if it works on your devices as well.

The other issue that I wrote about (iap.getLoadProductsFinished() always returning false when not calling loadProducts() with a listener) seems only to occur in the simulator. On a real device it works fine. I have an ongoing mail discussion with Happy Mongoose Game about that if you are interested.