in-app purchase template

_fellow developers,

I plan to publish e-magazines on Apple’s app store using in-app purchase. Unfortunately, I know nothing about in-app purchase. Could anyone here kindly share his/her sample code or template?

I understand I can download “in-app demo” on corona website, but that is not what I need.

Thank you in advance.

Cheers,
Henry

Sydney Australia_
[import]uid: 150748 topic_id: 29458 reply_id: 329458[/import]

Hey, Henry @Dr.Henry.Chen, have you tried the Sample Code that comes with Corona SDK? If not, you can find it inside the Corona SDK folder > SampleCode > Networking > InAppPurchase

Naomi [import]uid: 67217 topic_id: 29458 reply_id: 118314[/import]

**Thank you for your warm reply, Noami.
Yes, I have downloaded it already, but I don’t think it can be amended and then used for e-publication.

Regards,
Henry
^_^**

[import]uid: 150748 topic_id: 29458 reply_id: 118318[/import]

I am in the same both with Dr. Henry. I would really a like to see someone post the codes that they use for in-app purchase to unlock locked levels that works. I tried the sample code provided by Corona and read the forum and still can’t find a sample code that works . If some one has an entire piece of in-app purchase code that works can you please share it? Thank you for the help.
[import]uid: 104131 topic_id: 29458 reply_id: 118532[/import]

Hi Naomi,
I’ve been trying everything. Demoinapp purchase, the forum and still can’t seems to get in-app purchase to work in my app. I just want to give the first few levels for free and unlock the remaining levels. Do you have a template that can help me accomplish this? Thank you for your help.

[import]uid: 104131 topic_id: 29458 reply_id: 118734[/import]

@e1fabre, I don’t have IAP template, but here are links to documentation & threads that I carefully looked at when I set out to work on IAP:

http://developer.coronalabs.com/reference/in-app-purchases
http://troybrant.net/blog/2010/01/in-app-purchases-a-full-walkthrough/

Also, the example code supplied by d3mac123 helped me out (plus all the help I got from the very same thread). Maybe it could help you too? Here’s the link:
http://developer.coronalabs.com/forum/2011/10/13/app-purchases-help-needed#comment-60894

Naomi [import]uid: 67217 topic_id: 29458 reply_id: 118741[/import]

Thank you so much for your help, Naomi.
I will copy the example code and then do a thorough study.
Regards,
Henry
[import]uid: 150748 topic_id: 29458 reply_id: 118785[/import]

@ Naomi. Thank you so much for your help. I went through the code and tried it out several times and can’t seem to get it to work. The print statements in the loadProductsCallback and transactionCallback function are not executing. when I press the “continuebutton2” I was expecting to see the print statement in those functions. I would appreciate it much if you can glance through the code and see if I am doing anything wrong here. I’ve been on this for at least a week and I am not sure what I am doing wrong. A few questions please:

  1. in function savePurchase(product) i am using “savePurchase(validProducts[1])” is this correct?
  2. in function transactionCallback( event ) i am using “savePurchase(validProducts[1])” as my save product. Is this correct or should I be using a different format.
  3. Also when should I be seeing the print statement print (“purchased product”) in the loadProductsCallback function. The print statement is not executing even when I press the continuebutton2. Thank you for your help.

[code]
local loadProductsCallback = function( event )
– Debug info for testing
print(“loadProductsCallback()”)
print(“event, event.name”, event, event.name)
print(event.products)
print("#event.products", #event.products)

validProducts = event.products
invalidProducts = event.invalidProducts
unpackValidProducts ()
end

function savePurchase(product)
–savePurchase(1) – when saving product1
–savePurchase(“com.xxx.xxx”) – when saving product1
–savePurchase(validProducts[1])
–savePurchase(“validProducts[2]”) – when saving product2
–savePurchase(“validProducts[3]”) – when saving product3
–function on what should be save when user buy a product
end

function transactionCallback( event )
if event.transaction.state == “purchased” then
print (“purchased product”)
savePurchase(“product”) --you should enter here the product being purchased
–savePurchase(validProducts[1])
–store.purchase( {validProducts[1]} )

elseif event.transcation.state == “restored” then
savePurchase(“product”) --you should enter here the product being purchased
–store.purchase( {validProducts[1]} )
–savePurchase(validProducts[1])
elseif event.transaction.state == “cancelled” then
elseif event.transaction.state == “failed” then
infoString = "Transaction failed, type: ", event.transaction.errorType, event.transaction.errorString
local alert = native.showAlert("Failed ", infoString,{ “OK” })
else
infoString = “Unknown event”
local alert = native.showAlert("Unknown ", infoString,{ “OK” })
end
store.finishTransaction( event.transaction )
end

function setupMyStore (event)
store.loadProducts( listOfProducts, loadProductsCallback )
print (">>>>>>>>>>>>After store.loadProducts, waiting for callback")
end

local onbuyButTouch = function(event)
if event.phase==“ended” then
print(" iam here last")
local buyThis = function ( product )
if store.canMakePurchases then
print (“hello”)
–store.purchase( {product} )
print(“at store.can make purchases”)
store.purchase( {validProducts[1]} )
else
native.showAlert(“Store purchases are not available, please try again later”, { “OK” } )
end
end
– Enter your product id here
print(“at buythis product id”)
buyThis (“com.xxx.xxxxx”)
end
end

continuebutton2:addEventListener(“touch”, onbuyButTouch)[/code] [import]uid: 104131 topic_id: 29458 reply_id: 118795[/import]

@e1fabre, about savePurchase, please see this: http://developer.coronalabs.com/forum/2011/10/13/app-purchases-help-needed#comment-61889

Basically, it should be more like savePurchase(1). “1” is the index, or rather, 1st row of the IAP items you created in iTC – so if you have only one IAP item for sale, all you need is “1”.

print (“purchased product”) should show up on Xcode console when you successfully make the purchase, assuming you have your device hooked to your Mac and you use Xcode. And, by the way, personally, that’s the only way I’ve ever tested iOS version of the IAP, so I can’t tell you if there are any other place you might see it.

Just in case, you cannot test IAP using simulator or jailbroken iOS device. It can only be tested with your app installed on a device. And you need to test it against your own iTC sandbox.

I hope this helps.

Naomi
Naomi [import]uid: 67217 topic_id: 29458 reply_id: 118802[/import]

@ Naomi. Thank you so much. You are such a great help I think Ansca should hire you. I made the modification you suggested and I build it using the correct profile. I was I expected to see the “confirm your In-app purchase” window to pop up when I touch the continuebutton2 button. That did not happen. I am not sure why. Here’s the print statements I am getting from corona terminal when the project is loaded.

i am here 1
i am here 2
Calling: store.init
Calling: iap_setupMyStore
WARNING: store.loadProducts() is only supported on device.
>>>>>>>>>>>>After store.loadProducts, waiting for callback

When I click on the continuebutton2, I get these print statements:

iam here last
at buythis product id

I am still not sure if my “function savePurchase(product)”, " function transactionCallback( event )" and “local buyThis = function ( product )” functions are correct. My entire code is below. Can you please take a look at these functions and see if I am doing anything wrong? I’ve been trying to figure this out for a while and I am really not sure what is wrong. Thanks again for your help.

[code]

io.output():setvbuf(‘no’)

local store = require(“store”)

local listOfProducts = {
“com.mmm.xxxxxx”,
}

– In-App area

–local validProducts, invalidProducts = {}, {}
local validProducts = {}
local invalidProducts = {}

print (" i am here 1")
function unpackValidProducts()
print (">>>>>>>>>>>>>>Loading product list")
if not validProducts then
print(“not validProducts”)
native.showAlert( “In-App features not available”, “initStore() failed”, { “OK” } )
else
print(“looping through the invalidProducts”)
for numLoop=1, #invalidProducts do
native.showAlert( “Item " … invalidProducts[numLoop] … " is invalid.”,{ “OK” } )
end
end
if validProducts then
print("validProducts = " … tostring(validProducts))
print("validProducts[1].title = " … tostring(validProducts[1].title))
print("validProducts[1].description = " … tostring(validProducts[1].description))
print(“validProducts[1].price = " … tostring(validProducts[1].price))
print(“validProducts[1].productIdentifier = " … tostring(validProducts[1].productIdentifier))
end
end
print(” i am here 2”)

—=======================================
local loadProductsCallback = function( event )
– Debug info for testing
print(“loadProductsCallback()”)
print(“event, event.name”, event, event.name)
print(event.products)
print("#event.products", #event.products)

validProducts = event.products
invalidProducts = event.invalidProducts
unpackValidProducts ()
end

–===========================================
function savePurchase(product)
–function on what should be save when user buy a product
savePurchase(1) – when saving product1
end

–============================================
function transactionCallback( event )
if event.transaction.state == “purchased” then
print (“purchased product”)
–you should enter here the product being purchased
store.purchase( {validProducts[1]} )

elseif event.transcation.state == “restored” then
savePurchase(“product”) --you should enter here the product being purchased
store.purchase( {validProducts[1]} )
elseif event.transaction.state == “cancelled” then
elseif event.transaction.state == “failed” then
infoString = "Transaction failed, type: ", event.transaction.errorType, event.transaction.errorString
local alert = native.showAlert("Failed ", infoString,{ “OK” })
else
infoString = “Unknown event”
local alert = native.showAlert("Unknown ", infoString,{ “OK” })
end
store.finishTransaction( event.transaction )
end

–======================================
function setupMyStore (event)
store.loadProducts( listOfProducts, loadProductsCallback )
print (">>>>>>>>>>>>After store.loadProducts, waiting for callback")
end

-----=========================================
continuebutton2 = ui.newButton{
defaultSrc = “images/continue_40_40.png”,
overSrc = “images/continue_40_40.png”,
defaultX = 130,
defaultY = 50,
overX = 130,
overY = 50,
–onEvent = onbuyButTouch,
–onPress = onbuyButTouch,
–onRelease = onbuyButTouch,
id =“continuebutton”,
text =“lock”,
font =“Arial”,
textColor = { 239, 230, 110, 255 },
align = “center”,
size = 16,
}
continuebutton2.x = display.contentWidth * 0.5
continuebutton2.y = display.contentHeight * 0.5+60


local onbuyButTouch = function(event)
if event.phase==“ended” then
print(" iam here last")
local buyThis = function ( product )
if store.canMakePurchases then
print(“at store.can make purchases”)
store.purchase( {validProducts[1]} )
else
native.showAlert(“Store purchases are not available, please try again later”, { “OK” } )
end
end
– Enter your product id here
print(“at buythis product id”)
buyThis (“com.xxx.xxxxx”)
end
end

timer.performWithDelay (1000, function() print(‘Calling: iap_setupMyStore’); setupMyStore() end )
timer.performWithDelay (500, function() print(‘Calling: store.init’); store.init( transactionCallback) end )

timer.performWithDelay(2000, startStore)
[/code] [import]uid: 104131 topic_id: 29458 reply_id: 118837[/import]

@e1fabre, do you ever see loadProductsCallback() on your console print out? It’s supposed to print when loadProductsCallback function is fired. (See the print statement inside the function.)

And then, do you eventually see >>>>>>>>>>>>>>Loading product list on your console? It’s also supposed to print.

If not, you are not getting loadProductsCallback function to fire at all. And… are you testing your IAP routine on device? I could be wrong, but this warning you see “WARNING: store.loadProducts() is only supported on device.” sounds like to me that you are not testing the app on device. Like I mentioned before, you cannot test IAP using Simulator.

By the way, about savePurchase function, if you have only one product for sale, you don’t need to pass a param for product – meaning, you can call your savePurchase() function (without including “1”) and then do the saving routine (because your savePurchase function doesn’t particularly need to identify which product got purchased.)

Naomi

Edit: Just remembered to use the proper terms. As Peach noted in the following post, you need to connect your device to Mac and view the Xcode console to see the print output from device: http://developer.coronalabs.com/forum/2012/08/07/need-help#comment-118849

[import]uid: 67217 topic_id: 29458 reply_id: 118887[/import]

@ Naomi, Thank you so much for taking the time to help me. I was able to see most of the print statements in the console. The only ones I am not seeing are these below:
print("validProducts = " … tostring(validProducts))
print("validProducts[1].title = " … tostring(validProducts[1].title))
print("validProducts[1].description = " … tostring(validProducts[1].description))
print("validProducts[1].price = " … tostring(validProducts[1].price))
print("validProducts[1].productIdentifier = " … tostring(validProducts[1].productIdentifier))
However, I am getting an error in the console not sure what its means. See below. Any Idea? Thanks again.
Aug 8 21:25:06 enoss-iPad UIKitApplication:com.xxx.xxx.xx[0xa29c][543] : validProducts = table: 0x47f710

Aug 8 21:25:06 enoss-iPad UIKitApplication:com.xxx.xxx[0xa29c][543] : Lua Runtime Error: lua_pcall failed with status: 2, error message is: ?:0: attempt to index field ‘?’ (a nil value)
[import]uid: 104131 topic_id: 29458 reply_id: 118981[/import]

@e1fabre, it sounds like the validProducts returns empty table – meaning, it’s not fetching any valid products to fill up the validProducts table. You need to find out why you can’t fetch any valid products from the store…

Naomi [import]uid: 67217 topic_id: 29458 reply_id: 118990[/import]

@Naomi, You were correct. After struggling for weeks on this thanks to you I found out that my bundle ID did was not correct in my build.setting file (CFBundleIdentifier=“com.xxxx.xxxx.xx”,) You have really help me getting this solved. Thank yo so much.

My problem now is that I can not test the IAP. I was able to do it just once then all I am getting is this:

“You’ve already purchased this in-app purchase but it hasn’t been downloaded.”

I tried 3 different test users already. I read the forum and see some people had similar issues. I tried their solutions, so far nothing works. I even waited for almost 5 hours hoping that the account would reset. It didn’t happen. He’s what I’ve tried:

  1. create a new google gmail account.
  2. go to ituneconnect and create a test user with that gmail account
  3. signout in my ipad
  4. create a new build and load it in to the Ipad
  5. sign in with the new itunes account

It behaves as if it recognize the product was purchase already all the time regardless who the user is. As long as if it the same device it will give me that message. I am not sure how to get out of this I’ve tried everything.

I even tried deleting one of my test users. Whenever I tried to purchase, in addition to sign in with the new test users it keeps prompting me to put passwords for the deleted test user also. For some reason it remembers the deleted test user.
If you have any suggestion on this I would really appreciate it. Also for test users do I have to use a “real” email account or a fake one that doesn’t exist? I’ve been using real email accounts. Thanks to you, I can almost see the finish line :slight_smile:

thanks again for your help. [import]uid: 104131 topic_id: 29458 reply_id: 119205[/import]

When I was implementing IAP, I used this code from the code exchange. It was pretty easy to implement.
http://developer.coronalabs.com/code/super-simple-iap-1-line

Good luck! [import]uid: 47722 topic_id: 29458 reply_id: 119211[/import]

@e1fabre, I’ve seen many weird responses from iTC, but the one you’ve got is new to me (or rather, I don’t remember seeing it.) Is the alert custom made by you, or is it coming from iTC?

About the test users, you don’t need to create real email addresses for them. All I do is just add fake name and email address to test users at iTC, like so: Test User1 (= first & last name), test1@mywebsite.com (=email address that doesn’t exist, because I own the domain and I know test1@mywebsite.com is not a valid email address for this domain). This does the job.

What I do when all fails for no apparent reason (in my case, already-working-IAP would suddenly stop working for no reason that I could think of) is, wipe the device completely. I know it’s drastic, but it works for me. When I say wipe the device, I mean Settings > General > Reset > Erase All Content and Settings. It always works, clearing out whatever it is the iTC gave the device to mark it somehow (and I don’t use iCloud with my test iPod Touch – I figure I just have to return it to manufacturer default)

Not sure if you want to do this, but I am totally out of ideas at this point.

Good luck.

Naomi [import]uid: 67217 topic_id: 29458 reply_id: 119264[/import]

@Naomi,
I just want to thank you and report that thanks to you everything seems to works fine now. Resetting the device worked for me. I also found out that some time even resetting the device is not enough. From time to time I also have to shut the device down an order for me to get the “Download again” message.

One last question. Do I need a restore button? Do you have a restore button in your games for non-consumable goods? Thanks again for your help.

[import]uid: 104131 topic_id: 29458 reply_id: 119742[/import]

@e1fabre, glad to hear you got IAP sorted. About restore button, from what I gleaned, it does sound like you need a restore button for non-consumable goods. I’ve seen posts about Apple rejecting app without it. So I added it in my first game (called Beetle Bounce ) under Options screen.

Cheers,
Naomi [import]uid: 67217 topic_id: 29458 reply_id: 119764[/import]

@ Macmanman223, Thank you for the link.

@Naomi, I can’t thank you enough for helping me with my issues with IAP. My final question is based on the “Restore” button. From what i am reading from the forum, Apple is rejecting apps that don’t have a “Restore” button. I would hate to spend all this time working on an app and have it rejected. I found a sample code in the forum for a restore button. My questions are:

  1. in the Restore function sample code below where it said "

–If the product is called for restore do your restore code here
print (“Success! Product restored”)"

Do I put in the same unlock code I have under the “transactionCalback function”, if event.transaction.state == “purchased” there.

local transactionCallback = function( event )
if event.transaction.state == “purchased” then
print(“Transaction successful!”)
–my unlock code

  1. How do I test it to make sure that it works. What should I expect to see when I test the “Restore” function.
    Thanks again for your help.

[code]

---------------RESTORE BUTTON ------------

–Call Restore Function
local function callRestore()

–Restore Function
local function restorePurchases(event)
–Check for restored state
if event.transaction.state == “restored” then
–Product 1
–If restore state is true then check for a match on the product identifier
if event.transaction.productIdentifier == “com.xxx.xxx.xxx” then
–If the product is called for restore do your restore code here
print (“Success! Product restored”)

I am not sure what should go here?
store.restore()
end

–Finish Transaction
store.finishTransaction( event.transaction )
end
end

–Call the apple store
store.init( “apple”, restorePurchases )
–Lastly call the restore function
store.restore()
end
restorebutton: addEventListener (“tap”, callRestore)

–Restore button
local restore_Btn = display.newRect (0, 0, 50, 50)
restore_Btn.x = 200; restore_Btn.y = 200
restore_Btn: addEventListener (“tap”, callRestore)
[/code] [import]uid: 104131 topic_id: 29458 reply_id: 120274[/import]

@e1fabre, yes to your question #1. As for your question #2, it works the same way in sandbox as it would when your app goes live. Launch your app, unlock your app (using your test user account), delete the app from the device, then reinstall it and hit your restore button to unlock your app.

Good luck with finalizing your app!

Naomi

[import]uid: 67217 topic_id: 29458 reply_id: 120278[/import]