Skip to content

In App Purchases

In App Purchases (IAPs) are the primary source of revenue for the majority of mobile games today. However, despite their importance, adding support for IAPs is still a lengthy and complicated process. In addition to integrating your game with multiple separate app stores you must also ensure that purchases provided by players are valid and have not been faked. The process for this validation step also varies by vendor, requiring you to write separate verification code for each service.

ChilliConnect makes it easy to add safe and secure IAP support to your game. With ChilliConnect, you can retrieve associated IAP meta data at runtime allowing you to update the available purchases without requiring an app resubmission. ChilliConnect will also validate each purchase with the relevant vendor API and securely apply currency and in-game item rewards to the player's account.

This tutorials shows how to implement an end-to-end IAP flow in Unity and ChilliConnect with support for both iTunes and Google Play. The tutorial will cover:

  • Configuring IAPS products on both the Apple App Store and on the Google Play Store.

  • Defining two in-game Currencies, Coins and Gems, as part of a game Catalog within ChilliConnect

  • Fetching the player's currency balances from ChilliConnect to display in-game.

  • Defining Real Money Purchases within ChilliConnect that describe the available In App Purchases and associated currency rewards

  • Retrieving the available IAPs from ChilliConnect at run time and displaying to the player

  • Performing an IAP using Unity

  • Verifying, redeeming and securely applying the purchase rewards with ChilliConnect

The full Unity project from this tutorial is available on the ChilliConnect GitHub samples repository. This contains a fully executable project that you can configure with your own ChilliConnect Game Token and store details to run the code under your own account. You must also enable the Unity IAP Plugin from the Services menu and configure the plugin with your own Google Play and App Store settings.

 Download Sample Code

Configuring the Stores

Before we can configure ChilliConnect to redeem and verify IAPs we must add some products to both the Apple App Store and the Google Play Store.

Apple App Store

  • Go to your iOS App's dashboard on iTunes Connect and click the Features tab.

  • Click the plus button next to In-App Purchases to add a new IAP:

  • For this demo we are going to create consumable IAP for Coins and Gems (as both are spendable currencies) - one called "Bag of Coins" and the other "Bag of Gems":

  • Set the reference name, price, description and product ID (hang onto the product IDs as you'll need them later when setting up the Real Money Purchases on ChilliConnect):

  • Repeat for all IAP items

  • Note that you will need to upload a screenshot of the IAP in-game before submitting to Apple, but for development and testing these aren't required.

  • Add some sandbox users if you don't already have any setup via iTunes Connect Users and Roles. Sandbox users are allowed to purchase items without the app being published and are not charged real money. Make sure you sign in as this user on your device before testing.

 

Google Play Store

  • Go to your app's dashboard on Google Play Store and select In-app Products from the left hand menu.

  • Click on Add your first in-app product (you need to upload a signed APK first if you haven't already):

  • For this demo we are creating a "Managed" in-app product for Coins and Gems. As before, these will be named "Bag of Coins" and "Bag of Gems".

  • Set the Product ID and once again hang onto it as you'll need it later when setting up purchases on ChilliConnect:

  • Set the name, description and price:

  • Make sure to set the product to "Active":

  • Repeat for all IAP items:

  • Setup "Closed Alpha Testing" from the APK dashboard to add some test users.

  • Fix any issues in "Why can't I publish?" and then click Publish App to enable Alpha testing.

  • Jump to the ChilliConnect dashboard and select IAP Settings from the main Game view. Paste your Google Play License Key from the Services & APIs tab on the Google Play dashboard.

Defining the Catalog

Before we can continue we need to define the required game Catalog items within ChilliConnect. See the relevant section of the user guide for more information on the Catalog feature.

Currencies

For this tutorial we are going to add two currency types, "Coins" and "Gems".

  • Go to the ChilliConnect dashboard and select your game

  • Select Connect from the side bar on the left and then Catalog from the expanded menu.

  • Select Add Item in the top right corner and Currency from the drop down. This will open the Add Currency dialogue.

  • Enter the currency Name as "Coins" and Key as "COINS":

  • Repeat for another currency with name Gems and key "GEMS".

Now that the in-game currencies are created, we can define a purchase item that allows players to acquire currency.

Real Money Purchases

In ChilliConnect, a Real Money Purchase is a Catalog item that pairs an IAP product on the App Store, Google Play Store or Amazon Kindle Store with Currency or Inventory Item rewards.

When an IAP is purchased via one of the stores and redeemed through the ChilliConnect API, the purchase will be checked to make sure it is valid before the rewards are securely applied to the player's account. Using ChilliConnect to define and redeem In App Purchases means that the items awarded from an IAP can be changed dynamically through the ChilliConnect dashboard without requiring an app update. ChilliConnect will also store all player rewards to the cloud so they aren't lost if the player uninstalls the app.

Creating Real Money purchase items is very similar to creating Currency items:

  • Go to your ChilliConnect game's dashboard.

  • Select Connect from the side bar on the left.

  • Select Catalog from the expanded menu.

  • Select Add Item in the top right corner and Real Money Purchase from the drop down - this will open the Add Real Money Purchase dialogue.

  • Enter the Name as "Bag of Coins" and they Key as "BAG_OF_COINS".

  • Add the product identifiers for each store, using the same product ids you setup earlier - in the case of this tutorial, com.chilliconnect.iapdemo.bagofcoins

  • Use the "Add Reward" link to add 500 Coins as a reward.

  • Repeat this process for the Bag of Gems purchase.

This is what your game Catalog should look like at this stage:

Now the external setup is finished, the next stage is to start the Unity integration.

Fetching Player inventory

When the player launches the game, and is logged into ChilliConnect, we need to fetch their currency balances to make sure the local copy is up to date. The demo project requests the balances as soon as the player logs in and then updates the HUD showing how much of each currency the player has (check out InventorySystem.cs and InventoryUIController.cs in the demo project).

The following code requests the player's currency balances:

chilliConnect.Economy.GetCurrencyBalance(new GetCurrencyBalanceRequestDesc(), 
    OnCurrencyBalanceFetched, 
    (request, error) => Debug.LogError(error.ErrorDescription));

See Full Code 

The get currency balance response returns the balance of all currencies so we store balances in a dictionary of type and amount:

private void OnCurrencyBalanceFetched(GetCurrencyBalanceRequest request, 
        GetCurrencyBalanceResponse response) {

    foreach(var item in response.Balances)
    {
        AddItem(item.Key, item.Balance);
    }
}

See Full Code 

Fetching Available Real Money Purchases

Next, we have to populate the UI catalogue with the available Real Money Purchases that we created above ("Bag of Gems" and "Bag of Coins"). This allows the player is to select and purchase on of the available items (checkout CatalogueUIController.cs and IAPSystem.cs in the demo project).

chilliConnectSdk.Catalog.GetRealMoneyPurchaseDefinitions(desc, 
    OnAvailableItemsFetched, 
    (request, error) => Debug.LogError(error.ErrorDescription));

See Full Code 

The above code will fetch the available Real Money Purchases from ChilliConnect. The result of this request is then used to display the available purchase items to the player and to initialize the Unity IAP Plugin.

Unity IAP Plugin

This section will cover how to use the Unity IAP plugin. For more information see the Unity tutorial here. First the plugin needs to be imported; open the "Services" window in Unity and enable "In-App Purchasing" this will prompt you to import the IAP plugin.

Make sure that you add the correct bundle id for your app to the iOS/Android tab of "Player Settings" otherwise Unity will not be able to communicate with the store. For Google Play you will also need to provide your license key.

Create a class (in our demo this class is IAPSystem.cs) that implements the IStoreListener interface. IStoreListener is used by Unity to notify the class about initialization and purchase events from Unity IAP. Then initialize Unity IAP with the available products fetched from ChilliConnect.

private void OnAvailableItemsFetched(GetRealMoneyPurchaseDefinitionsRequest request, 
        GetRealMoneyPurchaseDefinitionsResponse response) {

    var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());

    foreach(var item in response.Items)
    {
        // Note: GetPlatformProductId is a helper method to grab the correct 
        // store id based on the current platform.
        builder.AddProduct(GetPlatformProductId(item), ProductType.Consumable);

        // We store the product id and key as we will need them later
        m_availableItems.Add(new Item(GetPlatformProductId(item), item.Key));
    }

    builder.Configure<IGooglePlayConfiguration>().SetPublicKey(
        "Public key can be found on Google Play dashboard under Services & APIs");

    UnityPurchasing.Initialize(this, builder);
}

See Full Code 

Note: The demo doesn't display the available items to the user until the Unity IAP plugin has finished initializing.

The nature of IAP systems means that some data (price for example) is held on the store and some data (rewards) are held by ChilliConnect. Once Unity IAP has finished initializing you will have a list of Real Money Purchase items from ChilliConnect and an equivalent list of IAP Products provided by the Unity IAP Plugin, so it makes sense to create a custom data structure that merges and holds the relevant data from each SDK.

public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
    m_unityStoreController = controller;

    foreach(var product in m_unityStoreController.products.all)
    {
        // Pair the store information with the data we have already pulled from ChilliConnect
        GetItem(product.definition.storeSpecificId).AddStoreData(
                product.metadata.localizedTitle, product.metadata.localizedPriceString);
    }
}

See Full Code 

At this stage of the demo project we have the code to:

  • Initialize ChilliConnect.

  • Create and login a player.

  • Fetch the inventory from ChilliConnect.

  • Fetch the available real money purchases from ChilliConnect.

  • Initialize Unity IAP.

The final step is to add the code to actually purchase an item.

Making a Real Money Purchase

The typical IAP purchasing flow involves several steps:

  1. Player chooses to purchase an item.

  2. Purchase request is made to the relevant app store via Unity IAP.

  3. Receipt is validated using ChilliConnect.

  4. If valid, rewards are added to the Inventory (cloud and local).

  5. Transaction is closed.

Unity IAP Purchase Request

Once the player has selected a purchase in the demo game, the CatalogueUIController will invoke the Purchase method on the IAPSystem that initiates the Unity IAP Purchase Request

public void Purchase(Item item)
{
    Product product = m_unityStoreController.products.WithID(item.ProductId);
    m_unityStoreController.InitiatePurchase(product);
}

See Full Code 

On successful purchase, a call will be made to the ProcessPurchase method of IStoreListener with information about the transaction. The receipt is then sent to ChilliConnect for validation and applying the configured rewards to the players account.

public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
{
    if(Application.platform == RuntimePlatform.IPhonePlayer)
    {
        string payload = ParseAppleReceipt(args.purchasedProduct.receipt);

        m_chilliConnect.Economy.RedeemAppleIap( GetItem(args.purchasedProduct.definition.storeSpecificId).RealMoneyPurchaseKey, payload, 
            (request, response) => OnPurchaseRedeemed(args.purchasedProduct, response.Status, response.Rewards), 
            (request, error)    => OnPurchaseRedeemFailedApple(args.purchasedProduct, error));
    }
    else if(Application.platform == RuntimePlatform.Android)
    {
        string purchaseData, dataSignature;
        ParseGooglePlayReceipt(args.purchasedProduct.receipt, out purchaseData, out dataSignature);

        m_chilliConnect.Economy.RedeemGoogleIap( GetItem( args.purchasedProduct.definition.storeSpecificId).RealMoneyPurchaseKey, purchaseData, dataSignature, 
            (request, response) => OnPurchaseRedeemed(args.purchasedProduct, response.Status, response.Rewards), 
            (request, error) => OnPurchaseRedeemFailedGoogle(args.purchasedProduct, error));
    }
    else
    {
        Debug.Log("Cannot redeem on this platform or on editor.");
        OnPurchaseCompleteEvent();
        return PurchaseProcessingResult.Complete;
    }

    // We return pending as we manually close off the purchase after ChilliConnect has verified and credited our account
    return PurchaseProcessingResult.Pending;
}

See Full Code 

A couple of important things to note about the above code: Firstly, each store has its own redemption method that takes the transaction receipt and the ChilliConnect Real Money Purchase key as an argument. The receipt JSON has to be parsed using the following methods (MiniJSON comes with the ChilliConnect SDK):

private string ParseAppleReceipt(string receipt)
{
    var wrapper = (Dictionary<string, object>)SdkCore.MiniJSON.Json.Deserialize(receipt);

    var payload = (string)wrapper["Payload"];
    return payload;
}

See Full Code 

private void ParseGooglePlayReceipt(string receipt, out string purchaseData, out string dataSignature)
{
    var wrapper = (Dictionary<string, object>)SdkCore.MiniJSON.Json.Deserialize(receipt);

    var payload = (string)wrapper["Payload"];

    var details = (Dictionary<string, object>)SdkCore.MiniJSON.Json.Deserialize(payload);
    purchaseData = (string)details ["json"];
    dataSignature = (string)details ["signature"];
}

See Full Code 

The second thing to note is that you must return PurchaseProcessingResult.Pending rather than PurchaseProcessingResult.Complete otherwise Unity will close the transaction without the player having yet be rewarded.

If the redeem call is successful, ChilliConnect will automatically add the rewards to the player's account (at this stage you could also fetch the inventory again but it is simpler just to keep the inventories in sync by awarding the items locally too).

As with the inventory, ChilliConnect will return the rewards as a flat list:

public void OnPurchaseRedeemed(Product product, string status, PurchaseExchange rewards)
{
    foreach(var reward in rewards.Items)
    {
        InventorySystem.Get().AddItem(reward.Key, reward.Amount);
    }

    m_unityStoreController.ConfirmPendingPurchase(product);
}

See Full Code 

Once the rewards have been added locally you should tell Unity IAP to close the transaction. If the transaction isn't closed Unity will call ProcessPurchase again on next app start with the same receipt. This can happen for a number of legitimate edge cases. Here are some of the most common ones that your app should handle:

Fraudulent purchases

It is not uncommon for cheaters to try and make purchases using fake receipts, in that case the error delegate is called with IapValidationServiceResponseInvalid. Just close off the transaction but don't award anything to the player.

public void OnPurchaseRedeemFailedApple(Product product, RedeemAppleIapError error)
{
    if(error.ErrorCode == RedeemAppleIapError.Error.IapValidationServiceResponseInvalid)
    {
        //Fraud or duplicate. Just close off without awarding
        m_unityStoreController.ConfirmPendingPurchase(product);
    }
}

See Full Code 

Duplicate purchases

The nature of mobile platforms means that the internet connection may be intermittent and lead to duplicate purchases. This usually happens when ChilliConnect has redeemed the purchase but the client drops out before closing the transaction (causing Unity to process the purchase again). If you are fetching the inventory on app start then the local user will already have the purchased items; therefore if a duplicate purchase occurs it is best not to re-award it locally but instead to display a message to the player explaining what has happened.

public void OnPurchaseRedeemed(Product product, string status, PurchaseExchange rewards)
{
    if(status != "InvalidRedeemed" && status != "InvalidVerificationFailed")
    {
        foreach(var reward in rewards.Items)
        {
            InventorySystem.Get().AddItem(reward.Key, reward.Amount);
        }
    }
    else
    {
        //Tell the user there purchases from last session have already been awarded.
        //or that it was fraudulent
    }

    m_unityStoreController.ConfirmPendingPurchase(product);
}

See Full Code 

Other Errors

Any other errors probably indicate an issue with the server or an issue with the game code. In those cases it is best to keep the transaction open and have Unity try again on next app start.

Troubleshooting

Here are some of the more common issues that can prevent IAPs from working:

General

  • Misspelling of product ids (either on the app stores or on ChilliConnect).

  • Not using a registered sandbox test user account.

  • Incorrect app bundle id specified in Unity player settings.

Apple

  • Using the wrong provision file (or not enabling IAP on the provision file).

Google Play

  • Not including the Google Play public key when initializing Unity IAP.

  • The version number of the APK that you upload must match the version number of the APK that you test with.

  • It can take up to 24 hours for newly added IAP to become available.

  • Not setting IAP as active on Google Play dashboard.

  • App has not been published for Alpha testing.

  • Test user has not Opted in via the testing URL (e.g. https://play.google.com/apps/testing/com.yourcompany.yourgame)

  • You have not added the license key to the IAP settings of the ChilliConnect dashboard.

Next Steps

You should now be familiar with the ChilliConnect Catalog feature and Real Money Purchases. If you want to explore more ChilliConnect features in this area try:

  • Adding some mixed reward real money purchases to create IAP bundle packs.

  • Using ChilliConnect Cloud Code to filter the available Real Money Purchases.

  • Using ChilliConnect Amazon redemption to add Kindle Fire support.