revUp - Updates and news for the LiveCode community
Issue 123 | November 24th 2011 Contact the Editor | How to Contribute

In-App Purchasing
Add features and powerups to your LiveCode apps and games, using In-App purchasing

by David Williams

This lesson will show you how to handle in-app purchasing in Livecode. This lesson assumes that you have the appropriate requirements for creating and handling in-app purchases, i.e. an apple developer program account. It would also be advisable to have a test account set up in iTunes Connect so that we can test our in-app purchases without spending any money.

1. Creating an in-app purchase

In order to use the in-app purchase with Livecode, we must first create it in iTunes Connect. From the front page of iTunes Connect, go to "Manage Your Applications", select the app for which you wish to create an in-app purchase, click "Manage In-App Purchases", and click "Create New". From there, follow the instructions to create the type of in-app purchase you wish to use. In the stack for this lesson, we will be using a consumable and a non-consumable purchase.

2. Setting up a stack to access in-app purchases

Screen_shot_2011-11-10_at_15

The first thing we will do is two buttons (one for consumable and one for non-consumable) and some code, which will allow us to interface with itunes connect and request the in-app purchases for download.

To our consumables purchase button, add the following code:

on mouseUp
mobilePurchaseCreate "com.runrev.purchasetest.consumable"
put the result into tID
mobileEnablePurchaseUpdates
mobilePurchaseSendRequest tID
end mouseUp

And similarly, add the following to our non-consumable purchase button:

on mouseUp
mobilePurchaseCreate "com.runrev.purchasetest.nonconsumable"
put the result into tID
mobileEnablePurchaseUpdates
mobilePurchaseSendRequest tID
end mouseUp

Finally, add the following code to the stack script:

on purchaseStateUpdate pPurchaseID

switch mobilePurchaseState(pPurchaseID)
case "paymentReceived"
answer "payment received!"

if mobilePurchaseGet(pPurchaseID, "productID") is "com.runrev.purchasetest.consumable" then
set the cConsumablesCount of this stack to (the cConsumablesCount of this stack + 1)
else
set the cNonConsumablePurchased of this stack to true
end if

mobilePurchaseConfirmDelivery pPurchaseID
mobileDisablePurchaseUpdates
break
case "error"
answer "Error occured during purchase handling:" & return & return & mobilePurchaseError(pPurchaseID)
mobileDisablePurchaseUpdates
break
case "cancelled"
answer "Purchase cancelled."
mobileDisablePurchaseUpdates
break
end switch

end purchaseStateUpdate

Here, the mobilePurchaseCreate command is used to generate an in-app purchase request within our app, and put the id of that in-app purchase request into the result. We tell the mobilePurchaseCreate command the identifier of the in-app purchase we are requesting - this must match the identifier of an in-app purchase that you have set up in iTunes Connect for the app. The mobileEnablePurchaseUpdates command will allow us to monitor the status of each in-app purchase request, using a specific built-in message, purchaseStateUpdate, which we can handle to check the status of the in-app purchase.

We then use the mobilePurchaseSendRequest command with the ID that has been put into the result - this will send the request and begin the purchasing process. The user will be prompted to enter apple ID details and so forth, in order to buy the product. The purchaseStateUpdate message will now be generated repeatedly while the purchasing process progresses - it is sent with a parameter denoting the ID of the specific purchase that the message is regarding. In the handler, we use the mobilePurchaseState function, passing it the purchase ID parameter, to check what the progress of that purchase is. Here we only want to take action if it returns "paymentReceived" (indicating that Apple has received payment for the purchase), or "error", or "cancelled".

In case of an error, we can use mobilePurchaseError with the purchase ID to find out the specifics of the error, and then use the mobileDisablePurchaseUpdates command to indicate that we are done with the purchase process (this is not essential in all circumstances, but is good practice regardless). In case of the user cancelling the purchase, we again want to use mobileDisablePurchaseUpdates. In case of payment being received, we can now take action in our app to finalize the purchase process - as there are multiple possible in-app purchases in this app, we will use the mobilePurchaseGet function to find out which in-app purchase we are dealing with. We pass the ID and "productID" to the function, which will return the identifier of the the purchase matching the ID we pass to the function. We can then take appropriate action for the in-app purchase that has been purchased, and use the mobilePurchaseConfirmDelivery command to confirm to Apple that payment has been received, finalizing the in-app purchase process on Apple's side.

One important note: the bundle identifier that you create the standalone application with (as specified in the standalone application settings) MUST match the bundle identifier tied to the in-app purchases in iTunes Connect.

3. Handling in-app purchases once they have been purchased

Screen_shot_2011-11-10_at_16

With the above, the purchase has been successfully handled. In this app, we are setting a custom property to indicate to our app that the purchase has been made. With the non-consumable purchase we simply set a custom property to true, but with the consumable in-app purchase, the user can purchase it as many times as they like so we simply increment a custom property to indicate how many times they have purchased it.

We can now use these custom properties to take action based on the in-app purchases the user makes (as of course, simply handling the in-app purchase process does nothing other than record the purchases with Apple and transfer money, etc). For this app, we're simply going to use the non-consumable purchase to change the background color of the stack and change the text of a field, and use the consumable purchase to make a graphic flash on and off briefly.

For the non-consumable purchase, we can use a setProp to implement this very quickly and conveniently:

setProp cNonConsumablePurchased pValue
set the cNonConsumablePurchased of this stack to pValue
if pValue then
set the backColor of this stack to 0,255,0
put "PURCHASED" into fld "purchased"
else
set the backColor of this stack to 255,255,255
put "NOT PURCHASED" into fld "purchased"
end if
end cNonConsumablePurchased

For the consumable purchase, we want the user to be able to activate it whenever they want rather than immediately, so we will use two handlers - a setProp to indicate to the user how many consumable purchases they have remaining, and a button to activate the consumable.

Our setProp will look like this:

setProp cConsumablesCount pValue
set the cConsumablesCount of this stack to pValue
put pValue into fld "consumablescount"
end cConsumablesCount

And our button should have this code:

on mouseUp
if the cConsumablesCount of this stack > 0 then
set the cConsumablesCount of this stack to (the cConsumablesCount of this stack - 1)
repeat with x = 1 to 10
wait 100 millisecs with messages
if the backcolor of grc "consumablegrc" is 255,255,255 then
set the backcolor of grc "consumablegrc" to 0,0,255
else
set the backcolor of grc "consumablegrc" to 255,255,255
end if
end repeat
set the backcolor of grc "consumablegrc" to 255,255,255
else
answer "you need to purchase a consumable first!"
end if
end mouseUp

This will let use 'use up' a consumable each time the user clicks the button, and only let them carry out the action we want if they have purchased a consumable in the first place.

4. Making purchases persistent

Diagram_display

One problem that you may have noticed, is that it is not possible to save a stack that is running under iOS (due to technical restrictions imposed by Apple). Therefore, our custom properties will revert to whatever values they at build-time, each time the app is closed. We therefore need to somehow save our custom properties, so that we can re-load them every time we open up the app on our mobile device.

One simple way of doing this is simply to add some code to our setProps which will write the value of the custom property to a text file located outside of the .app bundle - in this case, we'll use the documents folder. To this end, we will add the following handlers to our stack script, and call them at the end of our setProps for each custom property as follows:

on saveConsumablesCount
put the cConsumablesCount of this stack into url("file:" & specialFolderPath("documents") & "/consumablescount.txt")
end saveConsumablesCount

on saveNonConsumablePurchased
put the cNonConsumablePurchased of this stack into url("file:" & specialFolderPath("documents") & "/nonconsumablepurchased.txt")
end saveNonConsumablePurchased

setProp cNonConsumablePurchased pValue
set the cNonConsumablePurchased of this stack to pValue
if pValue then
set the backColor of this stack to 0,255,0
put "PURCHASED" into fld "purchased"
else
set the backColor of this stack to 255,255,255
put "NOT PURCHASED" into fld "purchased"
end if
saveNonConsumablePurchased
end cNonConsumablePurchased

setProp cConsumablesCount pValue
set the cConsumablesCount of this stack to pValue
put pValue into fld "consumablescount"
saveConsumablesCount
end cConsumablesCount

And we then simply load these values back in each time we open the app, by adding the following code:

on loadConsumablesCount
put (specialFolderPath("documents") & "/consumablescount.txt") into tPath
if there is a file tPath then
set the cConsumablesCount of this stack to url("file:" & tPath)
end if
end loadConsumablesCount

on loadNonConsumablePurchased
put (specialFolderPath("documents") & "/nonconsumablepurchased.txt") into tPath
if there is a file tPath then
set the cNonConsumablePurchased of this stack to url("file:" & tPath)
end if
end loadNonConsumablePurchased

on preOpenStack
loadNonConsumablePurchase
loadConsumablesCount
end preOpenStack

We now have a system which can control our in-app purchases simply by setting the value of the relevant custom properites, without having to worry about manually saving or loading them, or losing them.

Mark

About the Author

David Williams is a Software Developer for RunRev Ltd. His hobbies are coding, playing and listening to music, and gaming.

 

Main Menu

What's New

Be Thankful with LiveCode