Hi Alex
I did have a look at IAP badger before, but I didn’t find it easy to understand, there’s far too much going on.
While I appreciate what it’s trying to accomplish there’s information overload, do you know what I mean?
Not only that but the examples given are nearly 300 lines of code with spinners and what-not to decipher.
The same is true with Rob’s tutorial, “Understanding In-App Purchases”, a very good tutorial, never the less it still requires more reading and is bloated.
The basic workflow for your app involves:
- Determine the store your app is running on and initialize the store using store.init().
- If you think the app has been reinstalled (i.e. there is no settings file, etc.), then (for Google and Amazon) you can call store.restore() when your app starts because it is silent. Apple will prompt your app to login to the iTunes App Store when your app starts. It’s best to delay the restore until later. Apple wants you to have a button specifically to restore purchases.
- For Apple, Google Play V3 and Amazon, you can use store.loadProducts() to get a list of your items using localized names and prices. Google Play V2 does not offer this with the version of IAP that Corona SDK uses. When Google shows the purchase dialog, the localized values will be shown then. Many people will just hard code their items in a custom display.
- Offer a purchase button or display that allows the customer a chance to purchase your items. This should lead to a call to store.purchase().
- Inside the event handler function, perform whatever activities you need to unlock your app or process your purchase. For Google Play V3, this might be a good time to call store.consumePurchase() if the items is something like coins or gems that are being added to the app’s inventory immediately and can’t be tracked separately. Items like potions in a fantasy game, or purchasable power up’s can be consumed when they are actually used.
- Make sure to call store.finishTransaction() at the end, regardless of the transaction state. Failing to call this function can cause your app to receive too many transactions!
In addition, each vendor’s store variances create situations that you need to adapt to. Let’s look at a couple of key situations:
-
Consumables are never restored. You will never get a “restored” state that contains a consumable item. The reason is that these items are considered “used up” and there is no need to restore them. You will only get restored items for non-consumable items.
-
Google does not provided a “restored” state. Even if you call store.restore(), Goggle considers these “purchased” items. Thus, you need to determine the difference between “purchased” and “restored” if that’s important for the app. To handle this, you should store the transaction’s receipt and, when you receive a purchase request, you should compare against previous purchases and see if you found a matched receipt (this accounts for apps being deleted and re-installed). Note that you can’t save your receipts locally — instead, you have to setup an online method to store and retrieve these receipts. While this is not a trivial task, comparing these digital receipts (which are complex, encrypted chunks of data) makes it difficult for someone to fake a receipt during the restore phase. This is the best practice to help mitigate piracy. The code above does not, for brevity. What it does, however, is attempt to map purchases to restores when Google is involved.
-
If there is nothing to be restored, the event listener will not be called, so you should plan for this condition accordingly. If there is nothing to restore, there is nothing to do. Many people get snagged by this because they are looking for a “trigger” to say the process was complete. You should use a timer with a reasonable timeout to trigger your effect if there is no work to do.
-
Amazon and Google allow refunds, but they handle it differently. Google can generate a “refunded” state. If you see this state come through, you should have your app lock whatever feature that product ID unlocked. Of course, this only happens for non-consumable items. Products that are are consumed cannot be refunded. For Amazon, the state is “revoked”. Apple does not support refunds.
-
Apple triggers a store login for restores. The observant reader may have noticed that the store.init() sections above do not have a store.restore(). Google and Amazon will silently trigger restorations if the user is logged into the respective app store. Apple however, will prompt for the user’s password if they have not accessed the billing system in the last few minutes. Because of this, you don’t want a modal dialog to interfere with your users getting into the app and enjoying it. You can defer this restore until the user takes an action, until the place in your code where you actually need to determine their past purchases (or perhaps provide the user a “Restore past purchases” button in the interface). Apple will reject apps that do not call store.restore() in a proper manner.
While I’m writing this I’ve got 7 windows open…
https://github.com/happymongoose/iap_badger
http://happymongoosegames.co.uk/iapbadger.php?page=tutorial.markdown
http://developer.android.com/google/play/billing/billing_overview.html (This leads to EVEN MORE guides and tutorials)
https://coronalabs.com/blog/2013/09/03/tutorial-understanding-in-app-purchases/
https://docs.coronalabs.com/api/library/store/restore.html (These 3 lead to more docs, guides and tutorials)
https://docs.coronalabs.com/plugin/google-iap-v3/index.html
https://docs.coronalabs.com/guide/monetization/IAP/index.html
I’m going around in circles!
@JonPM
Right now I don’t need a unified approach for all the different stores, just Google.
@funkyvisions
I don’t care about restored and purchased because I’m only interested in Google, for now.
I’m pretty sure if I spend the time (I’ve spent over a week on this so far) and take out all the iOS stuff, consumable items, Amazon, encryption, hashes, Google V2 and so on… I will probably end up with working code a few lines long, eventually.
I was hoping that somebody here would say, “Hi QuizMaster, it’s easy! All I do is…”, instead of the usual “Did you read this tutorial?, Did you read the docs? Take a look at this link…”
Anyhow, thanks for your input so far, but I’m still stuck and more confused than before and ready to give up.
All I want to do is have 1 in-app purchase to unlock the full game with GPGS, is it really that difficult?