Correct IAP implementation?

So I am trying to create one IAP module that will work with all 3 stores (Apple, Google, Amazon).  The Apple and Google parts are working but not the Amazon.  Does this code snippet look correct?  If so, my problem may be elsewhere.  But so far Amazon is telling me that when they click on a button that is supposed to launch the IAP dialog nothing is happening. 

if system.getInfo("targetAppStore") == "amazon" or system.getInfo("environment") == "simulator" then store = require "plugin.amazon.iap" productID = googleProductList store.init( transactionCallback ) store.restore() elseif ( store.availableStores.apple ) then productID = appleProductList store.init( "apple", transactionCallback ) elseif ( store.availableStores.google ) then productID = googleProductList store.init( "google", transactionCallback ) end

That’s close to what I wrote in the IAP Blog post (http://www.coronalabs.com/blog/2013/09/03/tutorial-understanding-in-app-purchases/)

But I’m not sure hat your googleProductList is.  But all that looks right.

Yeah I pretty much copied it from there.  Here is the full iap.lua module:

module(..., package.seeall); local currentProductList = nil local appleProductList = { "com.mycom.app.50hints", --buyItem1 "com.mycom.app.unlimitedHints", --buyItem2 "com.mycom.app.categories1", --buyItem3 "com.mycom.app.general2" --buyItem4 } local googleProductList = { "com.mycom.app.50hints", --buyItem1 "com.mycom.app.unlimitedHints", --buyItem2 "com.mycom.app.categories1", --buyItem3 "com.mycom.app.general2" --buyItem4" } local callback = nil; --To get a price from any screen, just call iap.localizedPrices[XX] and replace the XX with the item number that you'd like localizedPrices = {}; --Fill out this section with all your product IDs from iTunes connect. local productID = {} function transactionCallback(e) local trans = e.transaction; if (trans.state == "purchased" or trans.state == "restored") then if (trans.productIdentifier == productID[1]) then --item1 \_G.bought = 1 print("success buying product 1! Give the user the item here, or in the callback (see comments above)"); settings.hintsRemaining = settings.hintsRemaining + 50 settings.adsEnabled = false settings:save() elseif (trans.productIdentifier == productID[2]) then --item2 \_G.bought = 2 print("success buying product 2! Give the user the item here or in the callback (see comments above)"); settings.unlimitedHintsPurchased = true settings.adsEnabled = false settings:save() elseif (trans.productIdentifier == productID[3]) then --item3 \_G.bought = 3 print("success buying product 3! Give the user the item here or in the callback (see comments above)"); settings.categories1Purchased = true settings.adsEnabled = false settings:save() elseif (trans.productIdentifier == productID[4]) then --item4 \_G.bought = 4 print("success buying product 4! Give the user the item here or in the callback (see comments above)"); settings.general2Purchased = true settings.adsEnabled = false settings:save() end elseif (trans.state == "cancelled") then print("player cancelled; you may want to show an alert here"); native.showAlert("Oops!", "Transaction cancelled by user", { "Dismiss" }); elseif (trans.state == "failed") then print("transaction failed"); native.showAlert("Oops!", "Please check your internet connection and try again.", { "Dismiss" }) elseif event.transaction.state == "refunded" then print("transaction refunded"); if (trans.productIdentifier == productID[1]) then --item1 settings.hintsRemaining = settings.hintsRemaining - 50 settings:save() elseif (trans.productIdentifier == productID[2]) then --item2 settings.unlimitedHintsPurchased = false settings:save() elseif (trans.productIdentifier == productID[3]) then --item3 settings.categories1Purchased = false settings:save() elseif (trans.productIdentifier == productID[4]) then --item4 settings.general2Purchased = false settings:save() end native.showAlert("Refund", tostring(trans.productIdentifier) .. " was refunded", {"Dismiss"}) end if (callback ~= nil) then callback(trans.state); end native.setActivityIndicator(false); store.finishTransaction(trans); end if system.getInfo("targetAppStore") == "amazon" or system.getInfo("environment") == "simulator" then store = require "plugin.amazon.iap" productID = googleProductList store.init( transactionCallback ) store.restore() elseif ( store.availableStores.apple ) then productID = appleProductList store.init( "apple", transactionCallback ) elseif ( store.availableStores.google ) then productID = googleProductList store.init( "google", transactionCallback ) end local function productCallback(event) print("showing valid products", #event.products) for i = 1, #event.products do print(event.products[i].title) -- This is a string. print(event.products[i].description) -- This is a string. print(event.products[i].price) -- This is a number. print(event.products[i].localizedPrice) -- This is a string. print(event.products[i].productIdentifier) -- This is a string. end print("showing invalidProducts", #event.invalidProducts) for i = 1, #event.invalidProducts do print(event.invalidProducts[i]) end end store.loadProducts(productID, productCallback) --These are the functions that you call from another lua file. -- Example: you'd call something like: iap.buyItem3(callback) if system.getInfo("targetAppStore") == "amazon" or system.getInfo("environment") == "simulator" then function buyItem1(callbackFunction) if store.canMakePurchases then store.purchase( productID[1] ); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem2(callbackFunction) if store.canMakePurchases then store.purchase( productID[2] ); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem3(callbackFunction) if store.canMakePurchases then store.purchase( productID[3] ); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem4(callbackFunction) if store.canMakePurchases then store.purchase( productID[4] ); native.setActivityIndicator(true); callback = callbackFunction; end end function restore(callbackFunction) store.restore(); native.setActivityIndicator(true); callback = callbackFunction; end else function buyItem1(callbackFunction) if store.canMakePurchases then store.purchase({ productID[1] }); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem2(callbackFunction) if store.canMakePurchases then store.purchase({ productID[2] }); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem3(callbackFunction) if store.canMakePurchases then store.purchase({ productID[3] }); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem4(callbackFunction) if store.canMakePurchases then store.purchase({ productID[4] }); native.setActivityIndicator(true); callback = callbackFunction; end end function restore(callbackFunction) store.restore(); native.setActivityIndicator(true); callback = callbackFunction; end end

And here’s how it’s being called from other scenes:

callbackFunction = function(state) -- function to handle response from app store if (state == "restored") or (state == "purchased") then if \_G.bought == 3 then -- user bought Categories pack, update DB and show message local onComplete = function() storyboard.gotoScene("scene-PuzzleCategories") end native.showAlert("Thank you", "You have bought the Categories Pack!", { "OK" }, onComplete) end if \_G.bought == 4 then -- user bought General #2 pack, update DB and show message local onComplete = function() storyboard.gotoScene("scene-PuzzleLevels") end native.showAlert("Thank you", "You have bought the General Pack #2!", { "OK" }, onComplete) end settings:save() -- save the DB \_G.bought = 0 -- reset bought code flag elseif (state == "cancelled") then elseif (state == "failed") then end end if store.canMakePurchases then -- check whether store is available iap.buyItem3(callbackFunction) else native.showAlert("Store purchases are not available, please try again later", { "OK" }) -- show message that shop not available end

So again everything works fine on iOS and Google, but Amazon is telling me when they click on a button to purchase an IAP, nothing happens.  Unfortunately I don’t have an Amazon device to test my app on.  If anyone would be willing to I could send the apk over…

What do you mean that “Amazon is telling you”.  Is this from a submission process?  Is it from the testing process?

Can you put in some prints to help trace through what’s happening?

Rob

Yes from their review process:

1.Install and launch the app 
2.Tap on play 
3.Tap on any IAP “categories pack” OR “Generalpack #2” 
4.Buttons not responding

I don’t have an Amazon device to debug with.  And like I mentioned it works fine on iOS and Android, so I’m not sure what the problem is exactly, and I can’t reproduce it.

Hmm I just checked my IAP items in the Amazon portal, and all of their statuses were “Live”.  I resubmitted them and now they all say “Approved”.  I wonder if this is the problem?  

Do you have any Android device?  I think its just a matter of getting the Amazon App store installed and then installing their IAP test app installed.  It could be as simple as not having the IAP items launched.

If you can’t test locally, you could go into Facebook and join the Beta test group there: 

https://www.facebook.com/groups/102481146589254/

And see if you can get someone there to test for you.  Any one there with Amazon access should be able to get a console log run and see your print statements.

Rob

Yes I did use their IAP test method and everything seemed to work fine.  I was getting the IAP pop up and the purchases were successful.  I think my best bet is to buy a Kindle or ask someone to debug for me…

Amazon sells referb’s of their devices.  That’s how I got my Kindle Fire.  They are a little cheaper than new and some people think referbs re better because they have a chance to make sure it all works well.

http://www.amazon.com/s/?ie=UTF8&keywords=certified+refurbished+kindles&tag=googhydr-20&index=aps&hvadid=28109642850&hvpos=1t1&hvexid=&hvnetw=g&hvrand=2926280481484869405&hvpone=&hvptwo=&hvqmt=b&hvdev=c&ref=pd_sl_7kub77dne1_b

That’s close to what I wrote in the IAP Blog post (http://www.coronalabs.com/blog/2013/09/03/tutorial-understanding-in-app-purchases/)

But I’m not sure hat your googleProductList is.  But all that looks right.

Yeah I pretty much copied it from there.  Here is the full iap.lua module:

module(..., package.seeall); local currentProductList = nil local appleProductList = { "com.mycom.app.50hints", --buyItem1 "com.mycom.app.unlimitedHints", --buyItem2 "com.mycom.app.categories1", --buyItem3 "com.mycom.app.general2" --buyItem4 } local googleProductList = { "com.mycom.app.50hints", --buyItem1 "com.mycom.app.unlimitedHints", --buyItem2 "com.mycom.app.categories1", --buyItem3 "com.mycom.app.general2" --buyItem4" } local callback = nil; --To get a price from any screen, just call iap.localizedPrices[XX] and replace the XX with the item number that you'd like localizedPrices = {}; --Fill out this section with all your product IDs from iTunes connect. local productID = {} function transactionCallback(e) local trans = e.transaction; if (trans.state == "purchased" or trans.state == "restored") then if (trans.productIdentifier == productID[1]) then --item1 \_G.bought = 1 print("success buying product 1! Give the user the item here, or in the callback (see comments above)"); settings.hintsRemaining = settings.hintsRemaining + 50 settings.adsEnabled = false settings:save() elseif (trans.productIdentifier == productID[2]) then --item2 \_G.bought = 2 print("success buying product 2! Give the user the item here or in the callback (see comments above)"); settings.unlimitedHintsPurchased = true settings.adsEnabled = false settings:save() elseif (trans.productIdentifier == productID[3]) then --item3 \_G.bought = 3 print("success buying product 3! Give the user the item here or in the callback (see comments above)"); settings.categories1Purchased = true settings.adsEnabled = false settings:save() elseif (trans.productIdentifier == productID[4]) then --item4 \_G.bought = 4 print("success buying product 4! Give the user the item here or in the callback (see comments above)"); settings.general2Purchased = true settings.adsEnabled = false settings:save() end elseif (trans.state == "cancelled") then print("player cancelled; you may want to show an alert here"); native.showAlert("Oops!", "Transaction cancelled by user", { "Dismiss" }); elseif (trans.state == "failed") then print("transaction failed"); native.showAlert("Oops!", "Please check your internet connection and try again.", { "Dismiss" }) elseif event.transaction.state == "refunded" then print("transaction refunded"); if (trans.productIdentifier == productID[1]) then --item1 settings.hintsRemaining = settings.hintsRemaining - 50 settings:save() elseif (trans.productIdentifier == productID[2]) then --item2 settings.unlimitedHintsPurchased = false settings:save() elseif (trans.productIdentifier == productID[3]) then --item3 settings.categories1Purchased = false settings:save() elseif (trans.productIdentifier == productID[4]) then --item4 settings.general2Purchased = false settings:save() end native.showAlert("Refund", tostring(trans.productIdentifier) .. " was refunded", {"Dismiss"}) end if (callback ~= nil) then callback(trans.state); end native.setActivityIndicator(false); store.finishTransaction(trans); end if system.getInfo("targetAppStore") == "amazon" or system.getInfo("environment") == "simulator" then store = require "plugin.amazon.iap" productID = googleProductList store.init( transactionCallback ) store.restore() elseif ( store.availableStores.apple ) then productID = appleProductList store.init( "apple", transactionCallback ) elseif ( store.availableStores.google ) then productID = googleProductList store.init( "google", transactionCallback ) end local function productCallback(event) print("showing valid products", #event.products) for i = 1, #event.products do print(event.products[i].title) -- This is a string. print(event.products[i].description) -- This is a string. print(event.products[i].price) -- This is a number. print(event.products[i].localizedPrice) -- This is a string. print(event.products[i].productIdentifier) -- This is a string. end print("showing invalidProducts", #event.invalidProducts) for i = 1, #event.invalidProducts do print(event.invalidProducts[i]) end end store.loadProducts(productID, productCallback) --These are the functions that you call from another lua file. -- Example: you'd call something like: iap.buyItem3(callback) if system.getInfo("targetAppStore") == "amazon" or system.getInfo("environment") == "simulator" then function buyItem1(callbackFunction) if store.canMakePurchases then store.purchase( productID[1] ); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem2(callbackFunction) if store.canMakePurchases then store.purchase( productID[2] ); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem3(callbackFunction) if store.canMakePurchases then store.purchase( productID[3] ); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem4(callbackFunction) if store.canMakePurchases then store.purchase( productID[4] ); native.setActivityIndicator(true); callback = callbackFunction; end end function restore(callbackFunction) store.restore(); native.setActivityIndicator(true); callback = callbackFunction; end else function buyItem1(callbackFunction) if store.canMakePurchases then store.purchase({ productID[1] }); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem2(callbackFunction) if store.canMakePurchases then store.purchase({ productID[2] }); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem3(callbackFunction) if store.canMakePurchases then store.purchase({ productID[3] }); native.setActivityIndicator(true); callback = callbackFunction; end end function buyItem4(callbackFunction) if store.canMakePurchases then store.purchase({ productID[4] }); native.setActivityIndicator(true); callback = callbackFunction; end end function restore(callbackFunction) store.restore(); native.setActivityIndicator(true); callback = callbackFunction; end end

And here’s how it’s being called from other scenes:

callbackFunction = function(state) -- function to handle response from app store if (state == "restored") or (state == "purchased") then if \_G.bought == 3 then -- user bought Categories pack, update DB and show message local onComplete = function() storyboard.gotoScene("scene-PuzzleCategories") end native.showAlert("Thank you", "You have bought the Categories Pack!", { "OK" }, onComplete) end if \_G.bought == 4 then -- user bought General #2 pack, update DB and show message local onComplete = function() storyboard.gotoScene("scene-PuzzleLevels") end native.showAlert("Thank you", "You have bought the General Pack #2!", { "OK" }, onComplete) end settings:save() -- save the DB \_G.bought = 0 -- reset bought code flag elseif (state == "cancelled") then elseif (state == "failed") then end end if store.canMakePurchases then -- check whether store is available iap.buyItem3(callbackFunction) else native.showAlert("Store purchases are not available, please try again later", { "OK" }) -- show message that shop not available end

So again everything works fine on iOS and Google, but Amazon is telling me when they click on a button to purchase an IAP, nothing happens.  Unfortunately I don’t have an Amazon device to test my app on.  If anyone would be willing to I could send the apk over…

What do you mean that “Amazon is telling you”.  Is this from a submission process?  Is it from the testing process?

Can you put in some prints to help trace through what’s happening?

Rob

Yes from their review process:

1.Install and launch the app 
2.Tap on play 
3.Tap on any IAP “categories pack” OR “Generalpack #2” 
4.Buttons not responding

I don’t have an Amazon device to debug with.  And like I mentioned it works fine on iOS and Android, so I’m not sure what the problem is exactly, and I can’t reproduce it.

Hmm I just checked my IAP items in the Amazon portal, and all of their statuses were “Live”.  I resubmitted them and now they all say “Approved”.  I wonder if this is the problem?  

Do you have any Android device?  I think its just a matter of getting the Amazon App store installed and then installing their IAP test app installed.  It could be as simple as not having the IAP items launched.

If you can’t test locally, you could go into Facebook and join the Beta test group there: 

https://www.facebook.com/groups/102481146589254/

And see if you can get someone there to test for you.  Any one there with Amazon access should be able to get a console log run and see your print statements.

Rob

Yes I did use their IAP test method and everything seemed to work fine.  I was getting the IAP pop up and the purchases were successful.  I think my best bet is to buy a Kindle or ask someone to debug for me…

Amazon sells referb’s of their devices.  That’s how I got my Kindle Fire.  They are a little cheaper than new and some people think referbs re better because they have a chance to make sure it all works well.

http://www.amazon.com/s/?ie=UTF8&keywords=certified+refurbished+kindles&tag=googhydr-20&index=aps&hvadid=28109642850&hvpos=1t1&hvexid=&hvnetw=g&hvrand=2926280481484869405&hvpone=&hvptwo=&hvqmt=b&hvdev=c&ref=pd_sl_7kub77dne1_b

Hey JonPM, do you happen to remember where you got this module from?

Hey JonPM, do you happen to remember where you got this module from?