New Google IAP Plugin and IAP Badger

We also rolled back to plugin.google.iap.v3 because with iap.billing we had a few complaints from customers that the app did not recognize their purchase, thus blocking access to their purchased content.

We have no idea what may cause this problem and we are unable to reproduce it on our own devices. Our app is a simple try-before-you-buy freemium app offering a single in-app purchase to unlock the full content.

Has anyone else switched to plugin.google.iap.billing? Anyone wants to share their experience?

Knock on wood, but I think I finally cracked it. In my explanation below, I’ll do my best to describe where I changed things in ways that are easy to search for, but I can’t reference line numbers because I’ve added some code and liberal commenting, which means nothing I have will line up with a fresh copy of iap_badger.lua.

As near as I can tell, the transaction was falling down in

if (transaction.state=="purchased") or (transaction.state=="restored") then

In Google transactions, IAP Badger waits a few milliseconds, checks to see if the products is a consumable and then attempts to consume it if it is.

timer.performWithDelay(10, function() store.consumePurchase({transaction.productIdentifier}) end)

Almost exactly half the time, this is successful and IAP Badger will receive [state] => "consumed" and then (if you have verboseDebugOutput=true) return "Consumption notification event".

The other half of the time, the Play Store returns:

[state] => "failed"
[errorString] => "Server error, please try again."
[isError] => true
[errorType] => 6

The transaction was successful, the user’s credit card was charged and they received their IAP. The only thing that didn’t work was that the consumption call failed. One time this threw a popup (search for: native.showAlert("Error", "Transaction failed: "), but the rest of the time it just silently failed to consume the purchase.

When the user attempts to purchase the same consumable again, they get the “You already own this.” popup, and then IAP Badger hits this section of code:

if (targetStore=="google") and (transaction.state=="failed") and (transaction.errorType==7) then

This goes on to turn the failed purchase into a restore event, which gives the user a free version of whatever it was they were trying to buy.

What I ended up doing was to follow Troy’s advice above and add a consume call to a fail event. It took me a few tries because I didn’t realize at first that his syntax is different than IAP Badgers. I was also concerned that doing a global consume would make it so users who had purchased non-consumable items would be unable to restore them if they reinstalled the game at some point down the road.

In order to capture the product identifier, way up at the top, around line 240, I added

local googleProductIdentifier

and then right after

local renamedProduct = getAppStoreID(productList[1])

I added

googleProductIdentifier = renamedProduct

(I suppose I could have simply declared renamedProduct outside of the function, but I wanted to keep all my changes very obvious.)

The final change was to go to

if (transaction.state==“failed”) then

and add

if ( targetStore == "google" ) then
store.consumePurchase( googleProductIdentifier )
end

After that, I never had a product fail to consume: Either it would work immediately, or it would get caught by the consume command in the fail routine.

Working under the idea that maybe IAP Badger wasn’t waiting long enough to call the initial consumption, I tried increasing the wait from 10 to 100. I did see a reduction in failures, but they didn’t go away entirely.

1 Like

@colinmorgan Thanks for sharing all this detailed information.

Any chance you can post the final IAP code in full?

Sure:

iap_badger.lua (90.7 KB)

I’m not in full production with this code yet. It’s working fine in beta, but I won’t know until next week if everything is working out in the wild. So, YMMV, Caveat emptor, etc.

Thanks, this does a lot of extra error handling things my code doesn’t but it does all the same basic calls. Maybe there are lots of errors causing my issues.

Maybe I will change to using this “IAP badger” instead of my code…

ok - I am using your code now - it seems to work pretty good, but after a few consumable purchases I am now getting “server error - please try again” popup - even though the purchase works and the user is getting their stuff.

Is there a way to handle this? turn it off?

I’m not sure I can give you too much more guidance other than what you will find going through the code yourself- I didn’t write IAP Badger and am by no means an expert on in-app purchase APIs.

I turned it off - there is an easy way. I have released an update using this code now - I just have to wait till I get another IAP…hopefully soon. Or I should borrow someones phone…

@joelutting If you use the same Google account (on device) as your developer account you can make free IAPs so you can test your app.

BTW, there are new “delayed purchase” statuses that you must now handle. This covers users making a purchase and then going to a store to actually pay for it. There could be hours or days between the purchase being started and the purchase being actually completed.

1 Like

Yeah I do this already, but the remove ads option is not consumable and since I have already bought it, it just says ‘you already own this item’. I tried refunding it, but still gives me this response. I have a second test account somewhere but forget its details and its a pain.

Anyway, got a friend to test it, waiting on whether it auto-refunds again.

Thanks for letting me know about the delayed payment option! Not sure how I should handle that? iap_badger code does not handle this?

Well I just tested that on one of my consumable purchases, and sure enough - it worked! I bought coins, then a few mins later, like magic, the coins appeared!

Cool when things just work!

You’ll get a “pending” status when this happens. What I do is I store the transaction details. On the next load perform a restore.

If the purchase is now paid you’ll get a “purchased” event. You simply need to cross-reference the transaction details with those you cached earlier and if you find a match then the purchase is legit and you can proceed as normal, award the player and consume the purchase.

This is new behaviour so I doubt the functionality exists in iap_badger.

its been 6 days since my test purchase and no refund! so it seems this worked - I used the iap_badger code provided above by colinmorgan. It seems to do everything right and it handles that delayed payment option to.
Just FYI - thanks everyone for your help.

I am noticing a lot of ‘payment declined’ with my IAP. Has anyone else been getting this? Is this normal?

Since I updated to the new API last week, my declined payment rate is about the same (+/- 3%) as it was before I switched billing plugins. Also, non-consumables that were purchased four days ago (post update) have not refunded, so that appears to be working correctly.

in the last week out of 7 purchases, 4 have been ‘payment declined’. I know I don’t get many purchases, but its a bit worrying.

It could very well be that the declined purchases were from the same person, repeatedly trying to get their purchase to go through.

3 different currencies so I don’t think so - I’ll just have to keep watching it.