As far as I know, you should always call finish() on non-consumable items. On Android they are called “managed” products.
As for consumables and unmanaged products, I think you should also call finish() and manage them yourself in your app. That is if a user reinstalls the game, it’s not required to restore such products. On iOS you instead use iCloud to restore the game progress and consumables.
On Android you can use Google Play Game Services or maybe Firebase to do the same thing for unmanaged products.
Again, as far as I know, if you don’t call finish(), after some time the purchase would be cancelled and the money would be returned to the user.
Calling finish() supposed to protect users from crashes during the purchase. You get the transaction, update internal values and only after that you call finish(). That way if the app crashes during update of the internal values - the user receives unfinished transactions when the app starts again.
Cool, thank you!!!
But I use only non-consumable items on ios and managed items on android. And if I call finish() on Android i can’t restore them later.
That mean a non-consumable purchase doesn’t work in defold at all =(
I’ve tested iap.restore() on iOS now and it works as expected. I have an app setup on iTunes Connect with a bunch of Consumable products and one Non-Consumable product:
My app is set to auto finish transactions in game.project.
I buy the consumable and non-consumable products as normal using iap.buy(). If I try to buy the non-consumable product again I get the “You’ve already purchased this” message:
And when I do a call to iap.restore() I get a callback to my iap.set_listener() defined function, with the state iap.TRANS_STATE_RESTORED. I can do this any number of times without any problems.
As for iap.restore() on Android you need to do as you’ve already outlined in your post above:
Don’t use auto finish transactions
Consume consumable products manually using iap.finish()
Use iap.restore() to get iap.set_listener() callbacks for any product that hasn’t been manually consumed yet
So I guess in order for you to get non consumable products to work in your game you need to do a couple of things:
Don’t use auto finish transactions
Always call iap.finish() on iOS
Call iap.finish() on Android for consumable products
Now I have next result on ios (i did not make a finish() of this purchase): https://www.youtube.com/watch?v=qbibMMqhf6w
(I forgot to show console, but I have no callback)
Should I create new account for tests? I have no possibility to continue work with this non finished purchaises?
Hmm, so that’s a consumable product that you haven’t called iap.finish() on? This is what happens for me:
iOS app auto_finish_transactions disable
Starting app:
iap.set_listener()
iap.buy() on a consumable product
NO call to iap.finish()
iap.buy() on the same product yields “You’ve already bought this”. No callback when I click through the popup (bug? maybe)
iap.restore() does nothing. This is expected since it only works for non-consumable products.
Restarting app:
iap.set_listener()
Callback for the unfinished purchase is invoked
NOTE: Multiple callbacks will be invoked if I have tried purchasing the same product multiple times. transaction.trans_ident is the same though.
So, from what I can tell there might be a bug with “You’ve already bought this” not resulting in any callback to the listener, but otherwise everything looks ok to me.
I try to finish purchase on ios and it works good (restore and repeat of purchase)
And now I have next unsolved questions:
Did I make everything right on android (I shouldn’t finish() purchaise)?
The purchase will not be canceled if i did not use finish() (android has only consume() method and has no method for confirm purchaise)?
What can I do with purchases that user already bouth, but not finished on ios (problem on video)? (I made it by mistake, but it posible after crash or some connection problem)
Yes. Do not call iap.finish() for non-consumable purchases. Google will keep track of this purchase for you. Every time you call iap.set_listener() or iap.restore() you’ll get a callback with any purchase that hasn’t been finished.
On iOS (and Android) you should get a callback to the iap.set_listener() function for every product that you haven’t called iap.finish() for. Aren’t you getting a callback? It works in my test app.
Works in my test app. I’m actually getting multiple callbacks. Once for every time I’ve tried to buy the product (same transaction.trans_ident though).
The same code works good on android, and on ios (if purchase was finished) too. But doesn’t work if I did not finish() a purchase.
Now I have 2 sandbox accounts where I cant buy or restore anything.
You mean that you’re getting the purchasing state as a result of the iap.buy() call and then nothing at all for iap.set_listener() (not even when the app is restarted and iap.set_listener is called again)?
It looks like (you can see it on video starting point 3):
buy non-consumable product without finish();
reinstall app;
try to buy this item and receive Purchasing callback;
tap buy and ok in ios windows (last is “already bought”);
and have no any other messages (in my case it is spin screen without callback), I checked it using DefCon and print in first line of callback (before all conditions).
I can restart an app and repeat all this points and receive the same result.