NOTE: This tutorial is outdated and has been replaced by the In-App Purchases (IAP) guide. Please refer to this guide for details and usage examples.
  1. Nice tutorial, thanks!

    However, it seems like the “refunded” state never gets called in a real world scenario.
    I’ve implemented this in my own app and done some testing. Refunds for IAP Purchases have to be initiated by the merchant. When I issue a refund in my Google Checkout page the event is never sent to the device.

    I may be missing something, but can’t figure it out.

  2. But how i can get localized price on android if there is no store.loadProducts() ?
    Now on iOS i get it by event.products[i].localizedPrice in the store.loadProducts() event handler.

    How to handle this on Android?

  3. Piotr,

    The Android Marketplace does not support fetching product information. So fetching localized prices is NOT an option. This means you should not display prices within your Corona app on Android. Instead, you should just list the products within your app and when you call store.purchase(), Android’s purchase screen will display the localized price.

    Have a look at our sample app “NetworkingInAppPurchase” that is included with the Corona SDK. Notice that we do not display prices within the app on Android, but we do show the prices on iOS. See that app’s setupMyStore() function on how we do this.

  4. Is it possible to allow for a similar “code once, run on different systems” approach Corona follows elsewhere? Specifying e.g. google as an argument seems to suggest developers will need to support two different approaches in the same program. I suppose both functionalities are very different behind the scenes, but is it possible to hide these differences as best as possible, like you guys do with the rest of Corona?

    Anyway, thanks!

  5. Adrian Tymes says:

    Is usesPermissions a new element in build.settings? Is there documentation for it yet? (Previously, permissions for android were set in settings->androidPermissions, rather than settings->android->usesPermissions.)

  6. Philipp,

    Specifying which store you will init with is absolutely essential unfortunately. You see, Google’s in-app purchase feature is not available on all devices or countries. This means that an Android app developer would need to support multiple in-app purchase solutions in order to maximize his/her profits. Ansca plans on adding at least 1 more in-app purchase solution on Android for this release, making this necessary.

    That said, if you omit the store name in the store.init() function call, then it will attempt to automatically select a store for you. So the store API is still backward compatible, but please realize that store.init() will fail if Google in-app purchasing is not available on that device/region, which is why we added the store.isActive property. Also realize that Google does not support store.loadProducts(), so you’ll have to handle that on your end too. There’s nothing Ansca can do about that because that is a limitation imposed by Google. Also, your product string keys might differ between Apple and Google, so that may be another gotcha.

    Please have a look at our sample app “Networking/InAppPurchase” that is included with the Corona SDK. That app supports both Apple and Google in-app purchases. I think what we’ve put together is an elegant solution considering the differences between store behaviors.

  7. Adrian,

    The “settings->android->usesPermissions” is new as of release build 704. No we have not documented it yet. We’re in the middle of reorganizing things so that all Android related settings are always under the android table… just like how it is for iOS… and eventually our Mac app solution. We still support the “androidPermissions” table and its permission settings will be correctly merged with the “usesPermissions” table when your app is built. In fact, you can put the billing permission in the “androidPermissions” table and it will still be injected into your built APK correctly.

  8. Apologies if this is a dumb question but does this work with any android store (eg Amazon App store, BN Nook and Google Play). Or just with Google Play (Android Market).

  9. I have a question regarding the “failed” event. I’d like to know how the transaction could “fail” in terms of timing.

    The reason why I’m asking this is because I have tested a conflicting cases for “cancelled” event. (Transaction can be cancelled before as well as after the “purchased” event, which would require two separate handling.) There’s a work-around for it, so it’s non-issue for me at the moment. (It is described here.)

    As for the “failed” event, I could be completely wrong, but I can think of two possible reasons why it could fail and when:

    Case 1: After the user places an order, Google Checkout approves the purchase, and my game triggers the “purchased” event. Then, somewhile later, as the Google Checkout processes the credit card payment, it finds a problem with the credit card and notifies the game that the transaction failed. At this point, the game will need to remove the purchased item.

    Case 2: After the user places an order, Google Checkout does not approve the purchase (because, say, the user’s credit card has already reached its max spending, etc.) and immediately notifies the game that the transaction failed. Under this scenario, the game would notify the user that he/she could not purchase the product.

    So, what I want to know is, how would I handle this two different scenario. Or are there two scenarios at all? Does “failed” event always happen only one of the two cases (most likely, the Case 2)? I’d so appreciate some clarification (since I can’t test this case to work out what to do.)

  10. Andrew,
    The Android in-app purchase feature is not available in our release build (#704) yet. It is only available via our daily builds, which only our paid subscribers have access to.

    This in-app purchase feature only works with Google’s Android marketplace. It does not work with Amazon’s or Barnes&Noble’s app stores. We plan on adding Amazon in-app purchase support in the near future. Barnes&Noble does not have an in-app purchase solution yet.

    Regarding Case 1 & 2, the “transaction.errorType” should be set to “invalidPayment”. Are you saying that the Android marketplace is sending you a PURCHASED notification and then reversing it saying it was invalid? If so, that’s the first I’ve ever seen that, but that would also be beyond our control since Corona merely “passes the message” to your Lua code. If the marketplace sends you a PURCHASED notification, then you app has no choice but to trust it because you have no means of predicting if the marketplace will later reverse it. You are the first person I’ve heard of that has mentioned this… but I’ll keep a sharp eye out for anyone else who has ran into similar issues.

  11. Joshua, thank you for the response. Yes, Android marketplace is sending me a PURCHASED notification immediately after the test user places an order. And because I was testing this process, I went to Google checkout the moment the PURCHASED notification game. There I saw the credit card payment being processed (i.e., payment has been authorized but actual payment has not been made yet). It looks like until the payment is fully processed, we have an option to cancel the order (instead of refunding the order). So, I cancelled the order, which sent the “cancelled” event notification to my game (as well as email notice to the test user). As I noted elsewhere, I can workaround it by never canceling any order but simply wait for the payment to go through, and then refunding the user instead.

    As for the FAILED event, I suppose it will happen before the PURCHASED event is sent? Let’s say, it could be caused by connectivity failure or by user’s credit card risk factor being too high? The more I think about it, the chances of FAILED event happening after the PURCHASED event is rather very small.

    Thanks again.


  12. In the iOS store, if I need to restore any product purchase all I need to call is:

    How to proceed in the case of Google Play for the refunds?

    • Alex, did you ever get an answer on this? Do we called store.refund() or something like that? I’m pretty confused on how to get refunds working. Can anyone else enlighten me? Thanks!

  13. Joshua –

    I have been working on adding in-app-billing to one of our products. I am running into a weird (intermittent) problem where Google Play doesn’t respond to the purchase request. My IAP Product is published, my app is signed and uploaded into Google Play, my test device has a different GoogleID than the one used for my Google Play developer account. When I push the purchase button (on Device), I sometimes get the proper purchase screen and can complete purchase. But most of the time, I get a page with the “Accept & Download” button, I push the button, and I don’t get a transactionCallback. I even tried the test code with my IAP Product, and the test code fails. So, I am fairly sure it has to do with either the way my product is setup, or the way I am conducting the testing. Any thoughts/pointers would be much appreciated.

  14. My android app has in-app billing, and i can buy the items in my app and the credit card has paid.
    And I want to send the recepit to our server to signature verification.
    I send the ‘event.transation.recepit’ to our server, the data was like 64382835091xx96 or 90328327062xx88, (xx are two numbers) . And our server can’t handle that data.

    How can I get the data that the server need to perform signature verification step through corona’s IAP api?

  15. Hi all,

    I notice the following when I run the sample app (InAppPurchase) on an Android device:

    1. The transactionCallback( event ) method is called twice when I click on “Lemonade refill” button.
    2. Printouts of the first call:
    event: storeTransaction
    state: purchased
    errorType: none
    3. Printouts of the second call:
    event: storeTransaction
    state: failed
    errorType: invalidClient

    My question is why are there 2 calls to transactionCallback( event ) and why did the 2nd call fail?

    Not sure if this helps but my Google account has been setup and I’m able to make purchases for other apps.

    Any help is appreciated.


  16. It looks like the transactionCallback is getting called on a separate thread, and it doesn’t have access to any of the variables defined in the file. Updates to the UI didn’t seem to work either.

    One suggestion for anyone out there that runs into this problem would be to use a custom event listener in the main thread, and use Runtime:dispatchEvent( event ) from transactionCallback to update the UI after a purchase.

  17. Hi guys, does anyone know if the current iteration of in-app billing for Corona and Android supports in-app billing version 3 API by Google?

    I have done some testing and can pull back and purchase consumable products, but subscriptions return “item not found”..


  18. This article should be updated as Corona had updated for Google in-app billing v3 and support for signature verification and other functions in Google billing V3. Any links to references and examples would be great.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>