In App Purchases

I am following a tutorial about setting up IAP for iOS, but I am having a problem. Here is the code:

local storyboard = require "storyboard" --local scene = storyboard.newScene() local widget     = require "widget" local store      = require "store" local scores = ice:loadBox("scores") local rabs = ice:loadBox("rabs")   --check if app is running in simulator local isSimulator = "simulator" == system.getInfo("environment")   -- Unbuffer console output for debugging io.output():setvbuf('no')     --remove for production code   local scene = storyboard.newScene()   local image,image2,closeBtn,myButton, text1,text2,text3 local validProducts, invalidProducts = {}, {} local descriptionArea local y = 0; b = 1; local buttons = {} local product   --forward declarations local image, player1,scoreText,rabText, text1, backBtn,myRoundedRect2 local rabbit1, rab1,rab2,rab3,rab4,rab5,line1,line2,line3,line4 local coins, coin1, coin2,coin3,coin4,coin5,buy1,buy2,buy3,buy4,buy5 local rab1Text,rab2Text,rab3Text,rab4Text,rab5Text local coin1Text,coin2Text,coin3Text,coin4Text,coin5Text,buyCoins,euro1,euro2,euro3,euro4   -- Called when the scene's view does not exist: function scene:createScene( event )     local screenGroup = self.view     print("createScene: shop\_new.lua ")      -- --image = display.newImage("images/Space theme dark(new).png", 0 ,0)     image2 = display.newImage("images/Space theme dark(new).png", 0 ,0)     screenGroup:insert( image2 )     -- --screenGroup:insert( image )               player1 = display.newRect( 0, 0, 0, 0 )     player1.text = display.newText("Points:", 120, 21, native.systemFont, 20)     player1.text:setTextColor(255,215,0)     screenGroup:insert( player1 )     screenGroup:insert( player1.text)     --player1.score = display.newText( "0", 100, 16, native.systemFont, 20)     --player1.score:setTextColor(255,215,0)     --player1.score.text = scores:retrieve("player1") or 0     score = scores:retrieve("player1") or 0     p1\_score = score          scoreText = display.newText( p1\_score, 200, 21, native.systemFont, 20)     scoreText:setTextColor(255,215,0)     screenGroup:insert( scoreText )          local rabs\_left = display.newRect(0,0,0,0)     --rabs\_left.score = display.newText("", 36, 265, native.systemFont, 24)     local rabbits = rabs:retrieve("rabs\_left") or 0     num\_of\_rab = rabbits     --print(num\_of\_rab)     rabText = display.newText( num\_of\_rab, 385, 21, native.systemFont, 20)     screenGroup:insert( rabText )     text1 = display.newText( "x", 365, 21,native.systemFont, 20)     screenGroup:insert( text1 )     --local text2 = display.newText( "Use coins to get more rabbits or \npurchase more coins.", 20, 60,native.systemFont, 20)          rab1 = display.newImage("images/rabbit\_40x40.png", 320, 10)     screenGroup:insert( rab1 )     -- coins = display.newImage("images/coins\_40x40.png", 120, 10)     -- scene.view:insert( coins )          myRoundedRect2 = display.newRoundedRect(0, 70, 480, 250, 0)     myRoundedRect2:setFillColor(255,255,255)     screenGroup:insert( myRoundedRect2 )          line1 = display.newLine( 0,130, 480,130 )     line1:setColor( 193,205,193 )     line1.width = 2     screenGroup:insert( line1 )          line2 = display.newLine( 0,190, 480,190 )     line2:setColor( 193,205,193 )     line2.width = 2     screenGroup:insert(line2)          line3 = display.newLine( 0,250, 480,250 )     line3:setColor( 193,205,193 )     line3.width = 2     screenGroup:insert(line3)          --line4 = display.newLine(           -- line4 = display.newLine( 0,270, 480,270 )     -- line4:setColor( 193,205,193 )     -- line4.width = 2     -- scene.view:insert(line4)     rabbit1 = display.newImage("images/bunny\_60x60.png", 10, 70)     screenGroup:insert( rabbit1 )     rab1Text = display.newText("x    15  ", 90, 90,native.systemFont, 24)     rab1Text:setTextColor(0,0,0)     screenGroup:insert( rab1Text )          text1 = display.newText(" =         0.89", 200, 90, native.systemFont, 24)     text1:setTextColor(0,0,0)     screenGroup:insert( text1 )     euro1 = display.newImage("euro.png", 250, 95)     screenGroup:insert( euro1)               rab2 = display.newImage("images/bunny\_60x60.png", 10, 130)     screenGroup:insert( rab2 )     rab2Text = display.newText("x    35    ", 90, 150,native.systemFont, 24)     rab2Text:setTextColor(0,0,0)     screenGroup:insert( rab2Text )          text2 = display.newText(" =         1.89", 200, 150, native.systemFont, 24)      text2:setTextColor(0,0,0)     screenGroup:insert( text2 )     euro2 = display.newImage("euro.png", 250, 155)     screenGroup:insert( euro2 )          rab3 = display.newImage("images/bunny\_60x60.png", 10, 190)     screenGroup:insert( rab3 )     rab3Text = display.newText("x    50   ", 90, 210,native.systemFont, 24)     rab3Text:setTextColor(0,0,0)     screenGroup:insert( rab3Text)          text3 = display.newText(" =         2.69", 200, 210, native.systemFont, 24)     text3:setTextColor(0,0,0)     screenGroup:insert( text3 )     euro3 = display.newImage("euro.png", 250, 215)     screenGroup:insert( euro3 )          rab4 = display.newImage("images/bunny\_60x60.png", 10, 250)     screenGroup:insert( rab4 )     rab4Text = display.newText("x   100    ", 90, 270, native.systemFont, 24)     rab4Text:setTextColor( 0, 0, 0)     screenGroup:insert( rab4Text )          text4 = display.newText(" =         4.99", 200, 270, native.systemFont, 24)     text4:setTextColor(0,0,0)     screenGroup:insert( text4 )     euro4 = display.newImage("euro.png", 250, 275)     screenGroup:insert( euro4 )               local currentProductList = nil          -- Product IDs for the "apple" app store.     local appleProductList =     {         -- These Product IDs must already be set up in your store         -- We'll use this list to retrieve prices etc. for each item         -- Note, this simple test only has room for about 4 items, please adjust accordingly         -- The iTunes store will not validate bad Product IDs          "com.myproduct1",         "com.myproduct2",         "com.myproduct3",         "com.myproduct4",     }          -- Product IDs for the "google" Android Marketplace store.     local googleProductList =     {         -- These product IDs are used for testing and is supported by all Android apps.         -- Purchasing these products will not bill your account.         "com.myproduct1.android",            -- Marketplace will always successfully purchase this product ID.         "com.myproduct2.android",         "com.myproduct3.android",            -- Marketplace will always cancel a purchase of this product ID.         "com.myproduct4.android",            -- Marketplace will always indicate this product ID as unavailable.         --"android.test.purchased",            -- Marketplace will always successfully purchase this product ID.         --"android.test.canceled",            -- Marketplace will always cancel a purchase of this product ID.         -- "android.test.item\_unavailable",    -- Marketplace will always indicate this product ID as unavailable.     }          -------------------------------------------------------------------------------     -- Displays a warning indicating that store access is not available,     -- meaning that Corona does not support in-app purchases on this system/device.     -- To be called when the store.isActive property returns false.     -------------------------------------------------------------------------------     function showStoreNotAvailableWarning()         if isSimulator then             native.showAlert("Notice", "In-app purchases is not supported by the Corona Simulator.", { "OK" } )         else             native.showAlert("Notice", "In-app purchases is not supported on this device.", { "OK" } )         end     end             local store = require("store")       function transactionCallback( event )     local infoString       -- Log transaction info.     print("transactionCallback: Received event " .. tostring(event.name))     print("state: " .. tostring(event.transaction.state))     print("errorType: " .. tostring(event.transaction.errorType))     print("errorString: " .. tostring(event.transaction.errorString))          native.showAlert(tostring(event.name),tostring(event.transaction.errorString),{"OK"})       if event.transaction.state == "purchased" then         native.showAlert("Purchased","State = purchased", {"OK"})         print("This here is getting to the purchased transaction state!")         infoString = "Transaction successful!"         print(infoString)         print(product)         if productIdentifier == "com.myproduct1" then             native.showAlert("Purchased","Getting here, 15 rabbits", {"OK"})             print("You have purchased 15 rabbits")             rabs:increment("rabs\_left",15)             rabs:save()             local rabs\_new = rabs:retrieve("rabs\_left") or 0             rabbits = rabs\_new         elseif productIdentifier == "com.myproduct2" then             native.showAlert("Purchased","Getting here, 35 rabbits", {"OK"})             print("You have purchased 35 rabbits")             rabs:increment("rabs\_left",35)             rabs:save()             local rabs\_new = rabs:retrieve("rabs\_left") or 0             rabbits = rabs\_new         elseif productIdentifier =="com.myproduct3" then             native.showAlert("Purchased","Getting here, 50 rabbits", {"OK"})             print("You have purchased 50 rabbits")             rabs:increment("rabs\_left",50)             rabs:save()             local rabs\_new = rabs:retrieve("rabs\_left") or 0             rabbits = rabs\_new         elseif productIdentifier == "com.myproduct4" then             native.showAlert("Purchased","Getting here, 100 rabbits", {"OK"})             print("You have purchased 100 rabbits")             rabs:increment("rabs\_left",100)             rabs:save()             local rabs\_new = rabs:retrieve("rabs\_left") or 0             rabbits = rabs\_new         end         --descriptionArea.text = infoString              elseif  event.transaction.state == "restored" then         -- Reminder: your app must store this information somewhere         -- Here we just display some of it         infoString = "Restoring transaction:" ..                             "\n   Original ID: " .. tostring(event.transaction.originalTransactionIdentifier) ..                             "\n   Original date: " .. tostring(event.transaction.originalDate)         print(infoString)         --descriptionArea.text = infoString         print("productIdentifier: " .. tostring(event.transaction.productIdentifier))         print("receipt: " .. tostring(event.transaction.receipt))         print("transactionIdentifier: " .. tostring(event.transaction.transactionIdentifier))         print("date: " .. tostring(event.transaction.date))         print("originalReceipt: " .. tostring(event.transaction.originalReceipt))       elseif  event.transaction.state == "refunded" then         -- Refunds notifications is only supported by the Google Android Marketplace.         -- Apple's app store does not support this.         -- This is your opportunity to remove the refunded feature/product if you want.         infoString = "A previously purchased product was refunded by the store."         print(infoString .. "\nFor product ID = " .. tostring(event.transaction.productIdentifier))         --descriptionArea.text = infoString       elseif event.transaction.state == "cancelled" then         infoString = "Transaction cancelled by user."         print(infoString)         --descriptionArea.text = infoString       elseif event.transaction.state == "failed" then                 infoString = "Transaction failed, type: " ..              tostring(event.transaction.errorType) .. " " .. tostring(event.transaction.errorString)         print(infoString)         print("IS it getting here when it fails???")         native.showAlert("Failed","Its failing here", {"OK"})         --descriptionArea.text = infoString              else         infoString = "Unknown event"         print(infoString)         --descriptionArea.text = infoString     end       -- Tell the store we are done with the transaction.     -- If you are providing downloadable content, do not call this until     -- the download has completed.     store.finishTransaction( event.transaction ) end       --initialize your tranaction callback with appropriate store(google or apple) if store.availableStores.apple then     currentProductList = appleProductList     store.init("apple", transactionCallback)     print("Using Apple's in-app purchase system.")     native.showAlert("Notice", "Using Apple's in-app purchase system", {"OK"})      elseif store.availableStores.google then     store.init("google", transactionCallback)     print("Using Google's Android In-App Billing system.") else     print("In-app purchases is not supported on this system/device.")     native.showAlert("Notice", "In-app purchases not working. Didn't init apple store", {"OK"})      end            local function purchaseItem(event)     --make sure you add { } around your product id as you need to send a table value... not a string!     product = "com.myproduct1"     store.purchase( {"com.myproduct1"})      end   local function purchaseItem2(event)     product = "com.myproduct2"     store.purchase( {"com.myproduct2"}) end local function purchaseItem3(event)     product = "com.myproduct3"     store.purchase( {"com.myproduct3"}) end local function purchaseItem4(event)     product = "com.myproduct4"     store.purchase( {"com.myproduct4"}) end   local function restorePurchases(event)     --no need to sepcify a product     store.restore()      end   --create a button that purchases an item local btnPurchase = widget.newButton {      defaultFile = "images/coins\_button.png",     left = 350,     top = 77,     onRelease = purchaseItem,     label = "Buy",     labelColor = { default={ 255, 250, 250}, over={ 0, 0, 0,} }, } screenGroup:insert(btnPurchase)   local btnPurchase2 = widget.newButton {      defaultFile = "images/coins\_button.png",     left = 350,     top = 137,     onRelease = purchaseItem2,     label = "Buy",     labelColor = { default={ 255, 250, 250}, over={ 0, 0, 0,} }, } screenGroup:insert(btnPurchase2)   local btnPurchase3 = widget.newButton {      defaultFile = "images/coins\_button.png",     left = 350,     top = 197,     onRelease = purchaseItem3,     label = "Buy",     labelColor = { default={ 255, 250, 250}, over={ 0, 0, 0,} }, } screenGroup:insert(btnPurchase3)   local btnPurchase4 = widget.newButton {      defaultFile = "images/coins\_button.png",     left = 350,     top = 257,     onRelease = purchaseItem4,     label = "Buy",     labelColor = { default={ 255, 250, 250}, over={ 0, 0, 0,} }, } screenGroup:insert(btnPurchase4)   -- local btnRestore = widget.newButton {      -- left = 20,      -- top = 100,     -- onRelease = restorePurchases,     -- label = "Restore" -- } -- screenGroup:insert(btnRestore)   local function onSceneTouch( self, event )         if event.phase == "began" then             local lastScene = storyboard.getPrevious()             print(lastScene)             local options = {             effect = "slideUp",             time   = 1000,             params =                  {                     index = index,                     fbLogin = fbLogin,                 }             }             storyboard.gotoScene( lastScene, options)             return true             end     end          backBtn = display.newImage("back.png", 0, 10)     backBtn.touch = onSceneTouch     backBtn:addEventListener( "touch", backBtn)     screenGroup:insert( backBtn )      end

I got a stripped down sample of the InAppPurchases sample from the Corona sdk. It works fine for android. I have ah-hoc provisioning profile, with iap enabled, I have a test user account, I have what I need upload to iTunes connect, but I can’t get this to work.

When I run on iPad, the call to init apple store, seems to work fine, doesn’t return an error.I have what I need uploaded to iTunes connect, but I can’t get this to work. When I run on iPad, the call to init apple store, seems to work fine, doesn’t return an error.

When I press the button the button to purchase a product, I don’t get prompted to enter my test user account details, and it hits the failed state of the transactionCallback function. 

Can anyone help?

Are you using a test user for IAP? You can create one in iTunesConnect. I am not sure you can use a proper appleID to make a purchase with a “non-production”-provisioning profile…

Sorry, i read too fast and did not catch that sentence… 

It’s OK jensto,

Yes I have a test user account setup. SInce I made the post, I read a lot of similar posts so I double checked everything, and remade my provisioning profile

and it actually worked. Now when I press one of the product buttons, it shows the native alert about purchasing the product in sandbox mode and prompts for the user Id.

Are you using a test user for IAP? You can create one in iTunesConnect. I am not sure you can use a proper appleID to make a purchase with a “non-production”-provisioning profile…

Sorry, i read too fast and did not catch that sentence… 

It’s OK jensto,

Yes I have a test user account setup. SInce I made the post, I read a lot of similar posts so I double checked everything, and remade my provisioning profile

and it actually worked. Now when I press one of the product buttons, it shows the native alert about purchasing the product in sandbox mode and prompts for the user Id.