Documentation

Did you find this helpful?

Getting Started with PlayFab, Unity IAP, and Android

This guide shows how to set up IAP using PlayFab, Unity + IAP Service and Android Billing API

Before we start

Setting up IAP may be tedious if you are not quite sure how different services are supposed to integrate and cooperate. The image below illustrates how Android Billing API and PlayFab work together to provide solid IAP experience for your client:

Start by setting up your product IDs and prices via Play Market. At this point all the products are "faceless" - they are just digital entities your player is able to purchase, but they have no meaning to PlayFab Players.

To make those entities useful we need to mirror them in PlayFab Item Catalogs: This will turn faceless entities into bundles, containers, individual items, each with it's own unique face: title, description, tags, types, images, and behaviors. All of those are linked to Market Products by sharing IDs.

The best way to access real-money items available for purchase is to use GetCatalogItems and GetStoreItems. These are the same API methods that are used by free-currency stores, so the process should be familiar.

The ID of the item is the link between PlayFab and any external IAP system. So, we pass item ID to the IAP service. At this point, purchase process starts. Player interacts with the IAP interface. In the end, if purchase is successful, you obtain a receipt.

PlayFab is then able to validate the receipt and register the purchase, granting PlayFab player items that he purchased. 

This is a rough idea of how IAP integration works and the following example shows most of it in action. 

Setting up a client application

This chapter shows how to configure a very primitive application to test IAP using PlayFab, UnityIAP and Android Billing API.

Prerequisites:

  • Unity project
  • PlayFab SDK imported and configured to work with your title

Our first step is setting up UnityIAP. Navigate to services (1), make sure "Services" tab is selected (2). Select your Unity Services profile or organization (3) and click "Create" (4):

Next, navigate to IAP Service (1):

Make sure to enable services (1) and click "Continue" (2):

A page with a list of plugins will appear. Click import (1):

Continue the Unity install and import procedure up to the point where it has imported all the plugins. Ensure plugins are in place (1). Then create a new script (2) called "AndroidIAPExample.cs":

"AndroidIAPExample.cs" will contain the following code (please refer to comments for further explanation):

using PlayFab;
using PlayFab.ClientModels;
using PlayFab.Json;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;

public class AndroidIAPExample : MonoBehaviour, IStoreListener {
    // Items list, configurable via inspector
    private List<CatalogItem> Catalog;

    // The Unity Purchasing system
    private static IStoreController m_StoreController;

    // Bootstrap the whole thing
    public void Start() {
        // Make PlayFab log in
        Login();
    }

    public void OnGUI() {
        // This line just scales the UI up for high-res devices
        // Comment it out if you find the UI too large.
        GUI.matrix = Matrix4x4.TRS(new Vector3(0, 0, 0), Quaternion.identity, new Vector3(3, 3, 3));

        // if we are not initialized, only draw a message 
        if (!IsInitialized) {
            GUILayout.Label("Initializing IAP and logging in...");
            return;
        }

        // Draw menu to purchase items
        foreach (var item in Catalog) {
            if (GUILayout.Button("Buy " + item.DisplayName)) {
                // On button click buy a product
                BuyProductID(item.ItemId);
            }
        }
    }

    // This is invoked manually on Start to initiate login ops
    private void Login() {
        // Login with Android ID
        PlayFabClientAPI.LoginWithAndroidDeviceID(new LoginWithAndroidDeviceIDRequest() {
            CreateAccount = true,
            AndroidDeviceId = SystemInfo.deviceUniqueIdentifier
        }, result => {
            Debug.Log("Logged in");
            // Refresh available items 
            RefreshIAPItems();
        }, error => Debug.LogError(error.GenerateErrorReport()));
    }

    private void RefreshIAPItems() {
        PlayFabClientAPI.GetCatalogItems(new GetCatalogItemsRequest(), result => {
            Catalog = result.Catalog;

            // Make UnityIAP initialize
            InitializePurchasing();
        }, error => Debug.LogError(error.GenerateErrorReport()));
    }

    // This is invoked manually on Start to initialize UnityIAP
    public void InitializePurchasing() {
        // If IAP is already initialized, return gently
        if (IsInitialized) return;

        // Create a builder for IAP service
        var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance(AppStore.GooglePlay));

        // Register each item from the catalog
        foreach (var item in Catalog) {
            builder.AddProduct(item.ItemId, ProductType.Consumable);
        }

        // Trigger IAP service initialization
        UnityPurchasing.Initialize(this, builder);
    }

    // We are initialized when StoreController and Extensions are set and we are logged in
    public bool IsInitialized {
        get {
            return m_StoreController != null && Catalog != null;
        }
    }

    // This is automatically invoked automatically when IAP service is initialized
    public void OnInitialized(IStoreController controller, IExtensionProvider extensions) {
        m_StoreController = controller;
    }

    // This is automatically invoked automatically when IAP service failed to initialized
    public void OnInitializeFailed(InitializationFailureReason error) {
        Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);
    }

    // This is automatically invoked automatically when purchase failed
    public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason) {
        Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
    }

    // This is invoked automatically when succesful purchase is ready to be processed
    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e) {
        // NOTE: this code does not account for purchases that were pending and are
        // delivered on application start.
        // Production code should account for such case:
        // More: https://docs.unity3d.com/ScriptReference/Purchasing.PurchaseProcessingResult.Pending.html

        if (!IsInitialized) {
            return PurchaseProcessingResult.Complete;
        }

        // Test edge case where product is unknown
        if (e.purchasedProduct == null) {
            Debug.LogWarning("Attempted to process purchasewith unknown product. Ignoring");
            return PurchaseProcessingResult.Complete;
        }

        // Test edge case where purchase has no receipt
        if (string.IsNullOrEmpty(e.purchasedProduct.receipt)) {
            Debug.LogWarning("Attempted to process purchase with no receipt: ignoring");
            return PurchaseProcessingResult.Complete;
        }

        Debug.Log("Processing transaction: " + e.purchasedProduct.transactionID);

        // Deserialize receipt
        var googleReceipt = GooglePurchase.FromJson(e.purchasedProduct.receipt);

        // Invoke receipt validation
        // This will not only validate a receipt, but will also grant player corresponding items
        // only if receipt is valid.
        PlayFabClientAPI.ValidateGooglePlayPurchase(new ValidateGooglePlayPurchaseRequest() {
            // Pass in currency code in ISO format
            CurrencyCode = e.purchasedProduct.metadata.isoCurrencyCode,
            // Convert and set Purchase price
            PurchasePrice = (uint)(e.purchasedProduct.metadata.localizedPrice * 100),
            // Pass in the receipt
            ReceiptJson = googleReceipt.PayloadData.json,
            // Pass in the signature
            Signature = googleReceipt.PayloadData.signature
        }, result => Debug.Log("Validation successful!"),
           error => Debug.Log("Validation failed: " + error.GenerateErrorReport())
        );

        return PurchaseProcessingResult.Complete;
    }

    // This is invvoked manually to initiate purchase
    void BuyProductID(string productId) {
        // If IAP service has not been initialized, fail hard
        if (!IsInitialized) throw new Exception("IAP Service is not initialized!");

        // Pass in the product id to initiate purchase
        m_StoreController.InitiatePurchase(productId);
    }
}

// The following classes are used to deserialize JSON results provided by IAP Service
// Please, note that Json fields are case-sensetive and should remain fields to support Unity Deserialization via JsonUtilities
public class JsonData {
    // Json Fields, ! Case-sensetive

    public string orderId;
    public string packageName;
    public string productId;
    public long purchaseTime;
    public int purchaseState;
    public string purchaseToken;
}

public class PayloadData {
    public JsonData JsonData;

    // Json Fields, ! Case-sensetive
    public string signature;
    public string json;

    public static PayloadData FromJson(string json) {
        var payload = JsonUtility.FromJson<PayloadData>(json);
        payload.JsonData = JsonUtility.FromJson<JsonData>(payload.json);
        return payload;
    }
}

public class GooglePurchase {
    public PayloadData PayloadData;

    // Json Fields, ! Case-sensetive
    public string Store;
    public string TransactionID;
    public string Payload;

    public static GooglePurchase FromJson(string json) {
        var purchase = JsonUtility.FromJson<GooglePurchase>(json);
        purchase.PayloadData = PayloadData.FromJson(purchase.Payload);
        return purchase;
    }
}

Create a new game object called "Code" (1). Add "AndroidIAPExample" component to it (2) (3). Make sure to save the scene (4).  

Finally, navigate to build settings. Make sure your scene is added to build (1). Make sure "Android" platform is selected (2). Navigate to "Player Settings" (3) and assign your package name. Note: make sure to come up with your own package name to avoid any Play Market collisions.

Finally, build the application as usual and ensure you have an APK safe and sound. We have no means to test it just yet: we need to configure Play Market and PlayFab which is described in the next chapters.

Setting up Play Market Application for IAP

This chapter descibes specifics on how to enable IAP for you PlayMarket Application. Setting up the application itself is beyond the scope of this guide, thus we assume you already have an application, configured to publish at least alpha releases:


Useful notes:

  • Getting to that point will require you to have APK uploaded. Please, use the APK we constructed in the previous chapter.
  • When asked to upload APK, you may upload it as Alpha or Beta application to enable IAP sandbox.
  • Configuring "Content Rating" will include questions about IAP enabled in the application.
  • Play Market does not allow Publishers to use or test IAP, so please, pick another Google account for testing purposes and add it a tester for your alpha/beta build

Once you have the application build published, navigate to "In-app products" (1). If asked for a merchant account, link or create one. Then click "Add New Product" (2):

Pick a "Managed Product" (1). Give it a well describing ID (2) and click "Continue" (3):

Play Market requires you to fill Title (1) and Description (2). Those, however, are not much of a use in our case. We will grab data item data exclusively from PlayFab service and only require IDs to match:

Scoll further and click "Add a price" button (1)

Enter a valid price (1). Notice how price is converted for each country independently. Click "Apply" (2):

Finally, scroll back to the top, and change status of the item to "Active" (1):

While this concludes configuring the app, we need a couple more tweaks. First, let us save the Licensing key. This will come in handy for linking PlayFab with Play Market. Navigate to "Services & APIs" (1). Then locate and save Base64 version of the key (2):

Next is enabling IAP testing. While sandbox is automatically enabled for Alpha and Beta builds, we need to set up accounts that are authorized to test the app. Navigate to Home (1), locate and click "Account Details" subtab (2). Find "License Testing" panel (3) and make sure test accounts are in the list (4) and that response is set to "RESPOND_NORMALLY" (5). Do not forget to apply the settings:

Play Market side should be set up at this point.

Setting up PlayFab Title

Our last step is configuring PlayFab title to reflect our products and integrate with Google Billing API.

Navigate to "Add-ons" (1), then navigate to "Google" add-on (2):

Fill in your package id (1), Google app license key (2) that you acquired in the previous chapter, commit by clicking "Install Google" (3):

Our next step is reflecting our Golden Sword item in PlayFab. Navigate to "Economy" (1), make sure "Catalogs" subtab (2) is selected and click "New Catalog" (3).

Give a version name for the catalog (1) and click "Save Catalog" (2):

If catalog has no items, it is automatically removed. That's why any new catalog comes with a pre-added item called "One". We can always create a new item, but, to keep things clean, let's modify the existing "One" item. Click the entry (1) in the list:

Set up item ID (1) to match exactly to the ID in Play Market. Next, give a display name (2) and description (3) to your item. Keep in mind that this data has nothing to do with Play Market itme title and description - it is totally independent. Assign price (4) to your item. In this guide IAP mainly refers to purchases for real money. That's why we use RM - special Real Money currency. PlayFab amount is defined in US Cents. Click "Save Item" (5) to commit:

Observe your item in the list (1):

This concludes setting up PlayFab Title.

Testing

You may now download the app using Alpha/Beta release. Make sure to use test account and a real android device. Once you start the app, you should see IAP initialed and one button representing your item. Click the button:

IAP purchase will be initiated. Follow Google Play instruction up to the point where purchase is succesful:

Finally, navigate to your title Game Manager dashboard and locate new events:

This means purchase was successfully provided, validated, and piped to PlayFab ecosystem.

At this point you have successfully integrated UnityIAP and Android Billing API into your PlayFab application.



Did you find this helpful?