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.