IAP Badger: a unified approach to in-app purchases

Hi Simon

Thanks for your reply. Unfortunately I do not have another Android to test on. I have tried on 3 daily builds including the latest one but all are giving me the same issue. The spinner simply hangs (not rotating) after tapping on restore. I am actually using most of your sample codes in my app.

It is strange that the purchase for Android works but not the restore.

I finally managed to resolve this issue. The problem occurs in my restore listener in which I call an alert dialog upon successful restoration. When that happens, it seems to hang the entire app (UI thread?).

Thank you so much for your assistance!

That does make sense - in IAP Badger, I had to put the call to consume a purchase (in Google Play) on a timer.

Glad you’ve got everything working.

Simon :slight_smile:

Hi, Simon.

First off, thank you for IAP Badger, it’s a great product. 

I’ve run into the following issue and am hoping you can help. Here is a summary:

*I installed and had IAP Badger running without any problems. At this time, I did not have the restore purchases feature hooked up. 

*I deleted one of my IAP called buyEndlessMode with an Apple ID of 003_EndlessMode. I deleted any instance of this IAP from the user’s perspective, but there were still some behind-the-scenes associated variables used in my code that seemed to be harmless. I also deleted the 003_EndlessMode product from the Apple App Store. 

*Everything worked fine after deleting 003_EndlessMode.

*Due to an unrelated issue, I had to delete and re-submit my IAP in the iTunes Connect. I resubmitted all my IAP with new Apple IDs and updated my IAP Badger code to reflect these new Apple IDs. My game ran fine on my phone, I was able to test in-app purchases and everything behaved as expected. 

*I just implemented the IAP Badger restore purchases features. 

*I built my app to my iPhone.

*I tested the restore feature on my phone and got the error:

"Runtime error

iap badger.storeTransactionCallback:

unable to find product

‘003_EndlessMode’ in a product for the apple store.

OK"

*When I clicked OK, my app crashed.

*I went back to my code and saw that some of the “harmless” remnants of buyEndlessMode were referenced in the restore code. I’m pretty sure this is what caused the error message to appear.

*After deleting the buyEndlessMode reference in the restore code, I rebuilt my app to my phone, but I still get the same error message as above as soon as my app starts and when I click OK the app crashes. Oddly, the variables buyEndlessMode and 003_EndlessMode and  no longer used anywhere in my code and this product has been deleted from the Apple App Store. 

Any ideas on how I can resolve this issue? 

Thanks so much!

Teagen

Hi Teagen,

Here’s what I think might be happening:

  • once a user purchases a non-consumable product, Apple say they have a persistent right to that product (that the developer can’t take away)
  • so a purchase for 003_EndlessMode is sitting on Apple’s servers for your Apple ID, even though you have now deleted that IAP from iTunes Connect (because the user has a persistent right to that IAP - that the developer can’t take away)
  • so when you run a restore, Apple’s servers are saying “this user purchased 003_EndlessMode”
  • then IAP Badger looks up 003_EndlessMode in the product catalogue and can’t find a product associated with it.
  • it then fires the error message, telling you that there is a critical problem that has to be resolved.

If I’m right, there are two ways forward with this:

  1. Assume this only ever going to happen on your account, because you’re the only person who ever purchased this IAP.  Test on another Apple ID, and if everything is okay, don’t worry about it.

  2. Add a dummy item to IAP Badger’s product catalogue for 003_EndlessMode (so IAP Badger finds the product code and is happy - even though you aren’t going to do anything with it).

I’d go with 2.

Hope this helps - don’t hesitate to get back in touch if it doesn’t  :slight_smile:

Kind regards,

Simon

Hey Simon,

I am just getting into IAP purchases and came across your plugin - looks awesome.    

I am just in the process of setting things up and noticed that “iap.loadProducts(loadProductsListener)” is not calling the listener (in the simulator with debug mode on).  However, if I change from the plugin to the github version it works perfectly (no other changes at all).

Cheer,

Craig

Hi Craig,

The two plug-ins are identical apart from a single line of code at the top, so something else must be going on - are you using the same catalogue across both your tests?

In debug mode, loadProducts  won’t contact the app store to get pricing information - it’ll use the simulatorPrice, simulatorDescription and simulatorTitle values in your catalogue instead (see this page).

Also be aware that in debug mode, loadProducts waits 2.5 seconds before calling your listener to fake the delay between the device contacting the app store and receiving a response (to emulate the response time you might get over a slow mobile signal).

If this information doesn’t resolve your issue, don’t hesitate to get back in touch.

Kind regards,

Simon

Hi Simon,

Thanks for the reply, getting through this IAP thing, everything as expected when simulating, just have to test live.    Your code makes things quite easy, thanks for all the effort.

In answer to your question,  I am changing nothing else, just that one line of code (see video), maybe the plugin conflicting with another plugin??

Also, I found another issue, the fake inventory items didn’t appear to be working as I expected,  maybe my interpretation of how it should work is wrong?  Anyway, since I was using the lua code from github I was able to get it working (code below).  

My understanding is that, it would look in the inventory for keys that were of a particular type and write these to the inventory file. However, they would never be found in the inventory file since they were never written.

I modified the code slightly to look in the “catalogue.inventoryItems” for those same keys, and if found then write them to the inventory file. 

Hope this makes sense.

--Goes through inventory, and enters random values for random-integer and random-decimal --products local function randomiseInventory() for key, value in pairs(catalogue.inventoryItems) do --Find the product in the product catalogue local product = value--catalogue.inventoryItems[key] --If the product is specified in the inventory... if (product) then --If the product type is random-integer... if (product.productType=="random-integer") then -- create a new table entry in the table and store the value for it. inventory[key] = {} inventory[key].value=math.random(product.randomLow, product.randomHigh) elseif (product.productType=="random-decimal") then inventory[key] = {} inventory[key].value=math.random(product.randomLow, product.randomHigh)+(1/(math.random(1,1000))) elseif (product.productType=="random-hex") then inventory[key] = {} inventory[key].value=string.format("0x%x", math.random(product.randomLow, product.randomHigh)) end end end end

Cheers,

Craig

Hi Craig,

This is completely due to (my) lack of clarity in the documentation.

The way this was intended to work was like this:

  • Once you have defined a ‘fake’ inventory item, you then have to add it to the user’s inventory (just like you would add a ‘real’ item to the user inventory when they make a purchase etc.)
  • So, to take the example from the very bottom of the tutorial, you would use **iap.addToInventory(“pixelGammaAdjust”) **the first time the game is run (or if the game detects the user’s inventory is empty).
  • The fake product ‘pixelGammaAdjust’ then sits in the inventory like a ‘real’ item.
  • Each time the inventory is saved, these fake value are randomised.

I’ll update the documentation to make that clear.

Simon

PS - I actually prefer your solution, but wonder if adding it to the code base might make this a breaking change.

Edit


  • I remember why I did this now - it was so fake items could be added and removed like any other items as the game progressed (letting the user inventory grow and contract with different values at different times).

Hey,

Awesome,  thanks for clarifying that.

Sorry to keep bugging you, but I seem to have run into another issue.  Everything works great on the device in debug mode, but there seems to be an issue when I go live and make a purchase (beta build).  The purchase goes through OK, but it seems to fail at the last step,  I think it is when it is consuming the purchase.  I made a video to show what is happening (videos are easier than trying to explain). 

I put a print table in your storeTransactionCallback function and this is what I see;

[transaction] =\> table: 0x8cb3e7e0 { [state] =\> "failed" [errorString] =\> "Signature verification failed for sku remove\_all\_ads (response: -1003:Purchase signature verification failed)" [isError] =\> true [errorType] =\> -1003 } 

When I click on the purchase again (start of the video), I get the error message straight away and the output tells me

[transaction] =\> table: 0x6f168220 { [state] =\> "failed" [errorString] =\> "Unable to buy item (response: 7:Item Already Owned)" [isError] =\> true [errorType] =\> 7 } 

Which is what make me think that the purchase is going through fine, but something is wrong with the consume…

Any ideas?

Craig

Hi there,

You can get response -1003 when you’re using the wrong license key for your app.

It also looks like you’re trying to purchase a non-consumable item more than once - you can only do this with consumable items.

Kind regards,

Simon

Thank Simon,

Feel like a bit of an idiot.  

The issue was my license key - I made the assumptions (I know :frowning: ) that since I already had a valid license key for Google Play Game Services that this would do, I did a quick check and the beginning and end were the same so I thought cool…

What I didn’t realize is that when I added IAP to the mix that the license key got updated and it was in fact very different.

Craig

No worries - glad you got it fixed  :slight_smile:

Good look with your app.

Kind regards,

Simon

Hi, Simon.

Belated thanks for your response (and I just noticed that you answered the same question a while ago on this thread, apologies for the repeat).

FYI, to anyone else going through this, I had put the dummy catalog items at the bottom of my product catalog. I no longer got the error for the outdated products, but I did start getting the same error for my current products. I was able to fix this by putting the dummy catalog items at the top of my product catalog. No more errors :slight_smile:

Best,

Teagen

Hi Simon,

Do you know if it there is a way of having a “mixed” consumable/non consumable  IAP?   I have implemented a MEGA IAP that includes the removal of ads and gems and a discounted price (I thought this was smart). I made this a non-consumable because I want the user to be able to restore the “remove ads”, however I discovered during testing that everytime I click on restore the user is gifted the gems all over again (this makes sense now I think about it).

The only solution I can think about is to disable the restore button after it has been pressed, however this still leaves me open to being taken advantage of since I use GPGS (i.e. someone uses the MEGA IAP, plays etc, saves state in GPGS, uninstalls, reinstalls which would make restore possible again, loads state using GPGS and continues with play).

Any ideas, or should I just remove the MEGA IAP?

Thanks,

Craig

I’d go with the simple approach and remove the Mega IAP - the amount of time you invest in getting this to work will probably outweigh the return.

The only other solution I can think of is to maintain a record of purchases on your own server - but then you’re introducing a whole new set of initial investment (time, cost, hassle) combined with an on-going investment (maintenance).

Simon

Hi, Simon (and anyone else reading that might have ideas on this issue). 

I’ve run into a new bug with purchasing. So far, I’m at a loss as to what’s causing the issue and I have no idea if it’s indeed related to IAP Badger (or my previous question on this thread), so I’m just throwing this question out here on this thread as a Hail Mary.

Below are the details.

Thanks for any insight you might provide.

Best,

Teagen

====Repro steps: ====

  1. Download and play live iOS game (currently on the Apple App store), version 1.1.6 which was released on April 15.

  2. Click to buy any in-app purchase, either a new theme or more color bombs.

  3. When the confirmation dialog appears asking if you want to purchase the item for $0.99, click <OK>.

====Actual result:====

After clicking the <OK> button on the confirmation dialog, the dialog closes and nothing else happens. The game picks up where it was but no purchase is made (either on client (aka user’s) side or on the server side (aka there is no record of a purchase in iTunes Connect). 

====Expected result: ====

After clicking the <OK> button, the user should be guided through dialogs to complete the purchase (for example, entering their Apple ID password), the user should be given their in-app purchase, and that purchase should be recorded in iTunes Connect. 

====Additional notes: ====

*When I build the game from Corona to my device and run it in sandbox mode, the purchase goes through just fine. It is only on the live build (downloaded from the app store) where I can find the bug. The bug appears to happen for all users. 

*The last recorded in-app purchase I received was on April 15 (according to my iTunes Connect account), which leads me to believe this bug is related to the last build I released, which was released on April 15. However, I cannot find any changes in that build related to purchasing. The product catalog issue I asked previously asked you about was only related to my local build and I have not yet pushed that code live, so I don’t think this issue is related to that previous issue. 

I found the solution!

On another website, I read that having outstanding contracts in your iTunes Connect account (in the Agreements, Tax, and Banking section), will keep IAP from going through on live builds, but will not affect IAP in the sandbox. After logging in to iTunes Connect, I saw that I had an outstanding contract. I approved it and a few minutes later my IAP started working. 

Thanks again for providing IAP Badger :slight_smile:

Just spotted a difference between the plugin and github source:  plugin requires a filename during init, github does not.  (I do all my own inventory management and file-keeping is why I noticed)  I’m not as concerned about that specific difference other than to cause me to wonder if there might be any “deeper” differences as well - is it expected that the two are in sync?  Thanks and cheers,

Hi there,

Thanks for bringing this to my attention - the two should be perfectly in sync at the moment, but it looks like for some reason the new version (ie. the one on Github) hasn’t uploaded properly to Corona’s servers.

This means the plug-in version is slightly out of date.

I’ll organise a fix in the next couple of days.

Simon