Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more

Tech

IAP Basics – What Do You Need To Know?

Posted on 7 November 2014

One great way of increasing the monetisation opportunities for your games and apps is to use in-app purchases (“IAPs”) within your project, which then allows players to purchase further items after their initial purchase price – it’s also a great way of enabling your game to be free on initial store purchase but then recoup some revenue later on.

IAPs can be a fairly complex system to integrate into your product, and many people send us support questions on this topic. We do have a series of FAQs available on the Helpdesk (and the Marketplace can help also) but in this article I’ll talk a little more about things to remember when working with IAPs. 

Please note that I will refer to the current version of GameMaker: Studio’s IAP support as the “new” IAP system even though it has been out for a while already (with the launch of 1.3). This is because many people are only now updating their products to this system in advance of other external factors, such as Google turning off support for the old system early next year.

 

Before We Begin

There is some important IAP terminology to be aware of before we start, and so I will explain the terms referred to in our documentation here:

 

  • Product – The individual bit of functionality you want to sell within your game.
  • Consumable Product – Also known as “unmanaged” or “non-durable”. A product which can be bought many times, such as coin packs.
  • Durable Product – Also known as “managed” or “non-consumable”. A product which lasts the lifetime of the game install (or beyond), such as disabling ads for the player.
  • Purchase – The user attempts to buy a product / the store says a sale has been made.
  • Consume Event – You clear a flag on the store so your player can repeatedly purchase the same product.
  • Restore Event – You ask the store which products the player has previously purchased.

 

It is important to note the distinction between “product” and “purchase” here, as in the previous IAP system GameMaker: Studio didn’t have as clear a separation of function names and terminology when describing developing IAPs into your project.

Also “consumable” and “durable” are the terms I will use here on, as they’re more clearly distinguished than the other combinations.

There is a lot more information on IAP concepts and the events you receive inside GameMaker: Studio covered in detail in the FAQ here, but note if you are new to IAPs it might be worth ensuring you read the entirety of this blog before jumping to that link.

 

Setting Up

IAPs work by sending an activation string off to the marketplace and then waiting for the store to respond to you. For this reason, most people will activate their IAP system on load of the game, but be aware this will add a slight delay to start-up.

When thinking about adding IAPs into your project, note that it is worth using the JSON method from the start – if you are updating a project from the old IAP method it might seem to you like more work than is required, but if it is a new project it is worth ensuring you support all possible marketplaces from initial launch (Amazon only allows JSON method) and knowing that you won’t have to modify your code later on. For more information on setting up for IAPs in this way, see: Activating In App Purchases Using JSON

There is also a method where you use DS maps for each of your products and then you add each map into a DS list and then iap_activate() the list. This is the more common approach and works just as well as the JSON method mentioned earlier (GameMaker: Studio supports both methods on as many platforms as is possible), but remember that you will not be able to publish on Amazon without extra work. This method is covered fully in the FAQ: In App Purchases Example

As stores begin to treat IAPs a little more carefully, it’s worth also thinking about how you present purchase options to your players.

 

  • Especially when dealing with games applicable to younger players, centralising IAPs on one “Store” screen is a great help for worried parents whose children play games, as colourful buttons for initiating purchases on every possible screen may see your game uninstalled in short order  – even consider adding a saveable password system for that screen!
  • And remember that if you support platforms which have no IAP store you will want to position UI elements such as purchase buttons in an unobtrusive manner anyway.
  • Do you need to sell IAPs in trial installs of your game? Many people would expect this functionality to be hidden or blocked.
  • Be aware that several stores now won’t list your product as “Free” if it includes IAPs (it will still sell for no cost, but the game can’t call itself “Free” and the store will make it clear to potential buyers that IAPs are available before they download your game).

 

In-App Events

Once the product list is activated, GameMaker then receives events for each IAP action taken by the user or from the store.

A Product event is received whenever you query information on a product with the store – functions such as iap_enumerate_all() allow you to ask for information on the list of products the store knows about for your title - so you could have different prices per store and retrieve the value to show in-game dynamically, for example. You will also get one of these for each product you activated immediately after the store has been successfully loaded, and this is a great way of confirming your IAP setup code is correct during testing.

A Purchase event is when the user has tapped a button to buy an IAP and you will get a matching event back from the store with the “receipt” information once the purchase is complete.

If your purchase was of a consumable product you then need to use iap_consume() on that product before it can be bought again by this player. The store will then return you a Consume event to confirm that the consume has taken place. Please note that you must ensure that the consume was successful before allowing another purchase attempt, as this can cause issues with many stores and could even crash your game. However, if your product is durable, then you must ensure it is not consumed, otherwise your player will lose that functionality and have to buy the product again. Apart from annoying your players, this can cause issues on some stores and even crash your game.

On all marketplaces you can ask the store to return a list of the durable products the player has previously bought, however there is a difference in what the sores actually return for this. On Apple stores you will get a Restore event for each product the player has bought, whereas on other stores you will get a Purchase event using the same values as when the player first bought the item, so you do need to handle purchases in two different ways if you want to support multiple stores. Please note also that Apple requires you to not automatically request this information for your player and instead add a button into your game for the player to check for any purchases they want to restore on demand. This is a submission condition your game will fail for, so ensure this is implemented before submitting to Apple.

There are other events for store load, etc., but these are not required during purchase/restore flow and are more for debug information or extra feedback if you wanted to provide this to your players. Otherwise, you can check the store status on demand using code like the following:

 

switch(iap_status())

{

    case iap_status_uninitialised: { draw_text(600, 20, "No IAPs activated"); break; }  

    case iap_status_unavailable: { draw_text(600, 20, "No store available"); break; } 

    case iap_status_loading: { draw_text(600, 20, "Connecting..."); break; }

    case iap_status_available: { draw_text(600, 20, "Ready"); break; }              

    case iap_status_processing: { draw_text(600, 20, "Working..."); break; }

    case iap_status_restoring: { draw_text(600, 20, "Restoring purchases..."); break; } // Only appears on iOS/Mac

}

 

Saving

A very important part of the IAP process is remembering that your user has bought products whilst playing the game. Remember also that the stores won’t track consumable purchases and certainly can’t tell you how many coins a player had bought, so you need to handle this within your code. The easiest way to do this is to build a DS map with your save details and then use ds_map_secure_save() / ds_map_secure_load() to manage this save file.

You should save values to say that a purchase is in progress also, to ensure that if something goes wrong and the connection is disrupted (or the user’s device does something unexpected) you can resume the purchase or consume later on.

You can also have your own web server for tracking purchase information, but this is beyond the scope of GameMaker: Studio’s documentation and this blog. 

 

 

Updating An Existing Project

Most of our Helpdesk contacts about IAPs nowadays are because of people unsure of a few specific points on how to update their code within an old project, so I’ll go over the important differences here.

1) The product index (the position the IAP appeared in your DS list you activated with the store) is still something you need to be aware of, but you’re now always better off just referring to the product ID directly. So your success code would be something like:

 

case iap_ev_purchase:

{ 

        iap_purchase_details(index, global.iapEventMap);

var product = global.iapEventMap[? "product"]; //Find out which product they have bought

// Now find out which IAP we need to give them

switch (product)

{

    case “noads”:  { … All of your success code here, then break; }

case “coins” : { … All of your success code here, then break; }

    }

}

 

Note that here we are checking the “product” key within the purchase details map, not the “index” of the map sent back from the store, like you did in the old IAP system.

2) iap_is_purchased() is no longer a valid function. Instead, you check the returned map from the store to confirm its purchase status, such as:

 

if (global.iapEventMap[? "status"] == iap_purchased) { iapSuccess(); }

       else { iapFail(); }

3) Remember that Apple platforms return a Restore event and so don’t trigger a repeat purchase, whereas other stores trigger a Purchase event when restoring old purchases. You will need to handle both, plus you might want to accommodate not showing thank-you messages and other feedback when restoring, but still show them when making a new purchase.

4) iap_product_details() gives an “id” key, not a “product” one anymore. (Please note that this currently needs to be fixed in the manual before the next 1.4 release.)

5) Note also that the consume event doesn’t always return a “consumed” key if the consume was successful, depending on the store. You should check for its absence or that it is true, and not fail any consume code if it is missing.

6) If you want debug info or to do some custom code in response to Consume events you will require iap_purchase_details() for generating your map to base your code off, not iap_product_details() as you might expect.

 

 

Getting Confirmation On IAP Status

Finally, if you want to confirm whether IAPs are working or if your code has an issue, consider downloading QuadBreak on your chosen store and ensuring it behaves the same, as this is our QA department’s own test project for IAPs.

You can also see the table here for a list of results when testing certain Studio releases (the last-checked release will always be named at the top). This page is updated when a new version of QuadBreak ships and/or when a major version of Studio is released – especially one which has a change which might impact on IAPs.

 

Conclusion

Hopefully, with this blog you’ve gained a good understanding of what IAPs can bring to your game or app, an overview of how IAPs work, and also some important points you must remember to implement in your system. You’ve also got some great links to more detailed information and sample code you can add into your project. Happy developing!

 

Back to Top