store.init was not working for Apple App Store IAP (in-app purchases)... or so I thought!

There are many important details that need to be set-up correctly to use the Corona store.* API for IAP (in-app purchases) on the App Store, so when my implementation was not working, I thought I’d gotten one of these details wrong. I spent a few hours going over everything with a fine-toothed comb and rereading the guides (staring with Corona’s IAP guide).  But there was something fundamental that I misunderstood about   store.init and I want to share my realization here.

When you call 

store.init( transactionListener )

the listener function is not called once the store is initialized.  I thought the listener was called when initialization completed, but that’s incorrect. You call the store.init() method and then you can call the other store.* methods right away, or so it seems.  To be on the safe side, you could make the call to store.init() and wrap the first call to another store.* method in a function that’s called in timer.performWithDelay().  In my tests, however, the code below works without introducing any delay.

local store = require 'store' local function transactionListener( event )     -- handle outcome of transaction (like store.purchase() )     store.finishTransaction( event.transaction ) end store.init( transactionListener ) if store.isActive and store.canLoadProducts then local function loadListener( event ) if event.products then for i=1,#event.products do print('Valid ID: ', event.products[i].productIdentifier ) end end end     local productIdentifiers = { 'com.newb.insights' } store.loadProducts( productIdentifiers, loadListener ) end 

I’ll try to suggest that this be clarified in the API documentation, but in the meantime, I hope this post can help others who, like me, assumed that you had to wait for store.init() to do its thing and let you know when it when store.* was ready.

Let me shed some light on this. There are three similar IAP libraries, store.* which is built-in to the core. Google Play and Amazon are implemented as plugins.  Because the API calls are very close to each other, most people want to write one set of code to work for all of them.

However, there is one big difference. For Google Play, store.init() does call its listener function after the init is successful. It is not a transaction event but a different event type. That way you can start calling other API functions upon successful init. However, for Apple, we currently don’t have such a “init complete” event. That’s because, for Apple, the .init() call can’t really fail since it’s just defining your transaction listener.  For Google Play IAP, work has to be done during .init().

Many people feel they need to call loadProducts() in main.lua. In most cases, you are not going to be showing prices and descriptions to users in main.lua and it’s a best practice to actually defer calling loadProducts until you are ready to actually show them.

Rob

Thanks for fleshing out the thread @RobMiracle and clarifying the differences between store.init() for the different IAP stores.

Since I’m only interested in the App Store for the time being, I hadn’t paid close attention to the Google Play related details.  I see there is clear documentation of the init event and documentation of store.init() for Google IAP.

The document for store.init() with the Amazon IAP plugin suggests that loadProducts() and transaction methods can be called without waiting for an init event.  Is that correct?

I believe so, but it’s still a best practice to defer loadProducts() until you need it.

Rob

Let me shed some light on this. There are three similar IAP libraries, store.* which is built-in to the core. Google Play and Amazon are implemented as plugins.  Because the API calls are very close to each other, most people want to write one set of code to work for all of them.

However, there is one big difference. For Google Play, store.init() does call its listener function after the init is successful. It is not a transaction event but a different event type. That way you can start calling other API functions upon successful init. However, for Apple, we currently don’t have such a “init complete” event. That’s because, for Apple, the .init() call can’t really fail since it’s just defining your transaction listener.  For Google Play IAP, work has to be done during .init().

Many people feel they need to call loadProducts() in main.lua. In most cases, you are not going to be showing prices and descriptions to users in main.lua and it’s a best practice to actually defer calling loadProducts until you are ready to actually show them.

Rob

Thanks for fleshing out the thread @RobMiracle and clarifying the differences between store.init() for the different IAP stores.

Since I’m only interested in the App Store for the time being, I hadn’t paid close attention to the Google Play related details.  I see there is clear documentation of the init event and documentation of store.init() for Google IAP.

The document for store.init() with the Amazon IAP plugin suggests that loadProducts() and transaction methods can be called without waiting for an init event.  Is that correct?

I believe so, but it’s still a best practice to defer loadProducts() until you need it.

Rob