Homa Belly Purchases

Table of Contents

Introduction

In this section, you will learn how to use Homa Belly Purchases to offer In App Purchases (and Subscriptions) to your end users.

Prerequisites

Your Homa Belly manifest should have the homabelly_purchases package on it and all the product SKUs properly configured. If you don't have it, please ask your publish manager.

Catalog

The Catalog is where all the In-App products are configured within the Unity project. This Catalog will be automatically configured with Homa Lab remote configuration the very first it is integrated.

💡 The Catalog can be modified within Unity Editor at any time. Any change on it will be preserved in further Homa Belly updates unless the Restore to defaults button is pressed.

Hence, the number of products, product IDs, SKUs, etc... can be modified to best match the corresponding project

  • Default Api Key: should never be changed unless asked to.

For each Product the following fields are available:

  • Product ID: internal ID for the seek of simplicity. It can be modified as per the developer needs
  • Produt Type: CONSUMABLE, NON_CONSUMABLE or SUBSCRIPTION
  • Product Sku: default Sku of the product to be used in case there is no overrides
  • Override Platform SKUs: different SKUs per platform for a product

In the above Catalog example, the No Ads product could be queried either by its ID (com.homagames.purchases.default.noads) or its platform dependent sku (android.no.ads.sku or ios.no.ads.sku) obtaining the same results at any operation.

⚠️ Starting with Homa Belly Purchases v1.6.2 a new field for BasePlanIds added to the subscriptions items in the catalog since Google Play Requires games to support BasePlans with Billing Library version 5 please check our documentation to learn more about how to use BasePlans.

Adding or removing products

If there is the need of adding or removing a product it can be done with the rightmost available buttons. This modifications will be conserved unless Restore to defaults button is pressed.

Restoring Catalog

If a Catalog restore is required either because it was wrongly configured or because the Homa Belly Manifest was updated, just need to press Restore to defaults, which will clean-up any modifications in the Catalog and configure it from scratch with the remotely configured values.

Initialization

For a simple initialization, call HomaStore.Initialize(). Do this at the very beginning of your game, so the store will have time to fully initialize before the user reaches the store page.

public class PurchaseDemo : MonoBehaviour
{
    private void Start()
    {
        // Initialize
        HomaStore.OnProductsRetrieved += OnProductsRetrieved;
        HomaStore.Initialize();
    }

    private void OnProductsRetrieved(Product[] products)
    {
                // Here you will receive the complete list of products
                // fetched from the Store in case you want/need to iterate over
                // them. Use this to display items, price, etc...

                // You can ignore this callback if using ProductButtonHelper script
    }
}

Initialization flow

After invoking HomaStore.Initialize() you can expect the following flow to be automatically executed and invoking the corresponding callbacks.

  • Flow diagram

    flow

Using Product Button Helper

Homa Belly Purchases offers a ready-to-use script to facilitate your work while configuring an In App Purchase Button: ProductButtonHelper. Just attach this script to your UI Button and configure the following:

  • OnClick: bind the ProductButtonHelper.InitiatePurchase method to the OnClick button event. This wil trigger the purchase process
  • Android Product ID: the id/sku you want this button to show when running on Android devices (can be the same than Apple Product ID)
  • Apple Product ID: the id/sku you want this button to show when running on Apple devices (can be the same than Android Product ID)
  • UI: optional properties to bind the product title, description and price to Unity UI Texts. Also an optional fullscreen loading UI can be toggled to appear when a purchase process starts
  • OnProductFetched: link any method you want to be executed once the product is fetched from store. Usually this method modifies the UI and updates the pricing string, the title, etc... Maybe you can also hide your whole GameObject while the product is not fetched. Totally up to you.
  • OnPurchaseSucceeded: method that will be invoked when the purchase has been succesful for the configured produt id/sku
  • OnPurchaseFailed: method that will be invoked when the purchase has failed for the configured produt id/sku
  • OnPurchaseRestored: method that will be invoked when the purchase restore has been completed. This method will receive all products within the Catalog (purchased and not purchased ones) with their status up to date so you will be able to check if they are purchased or not.

5-2

Initiating a purchase manually

If you use your own implementation and want to initiate a purchase for a product, call HomaStore.PurchaseProduct and listen to HomaStore.OnPurchaseSuccess and HomaStore.OnPurchaseFailure callbacks.

private void Awake()
{
    // Start listeining Homa Store events
    HomaStore.OnPurchaseSuccessForProduct += OnPurchaseSuccessForProduct;
    HomaStore.OnPurchaseFailedWithError += OnPurchaseFailedWithError;
        HomaStore.OnPurchaseInitiatedForProduct += OnPurchaseInitiatedForProduct;
        HomaStore.OnPurchaseFinishedForProduct += OnPurchaseFinishedForProduct;
}

private void OnDisable()
{
    // Stop listening Homa Store events
    HomaStore.OnPurchaseSuccess -= OnPurchaseSuccess;
    HomaStore.OnPurchaseFailed -= OnPurchaseFailure;
}

public void InitiatePurchase(string productSku)
{
        // Initiates a purchase process. Until this process has not been
        // completed (see OnPurchaseFinishedForProduct) starting another
        // purchase process won't be allowed: will result in failure
    HomaStore.PurchaseProduct(productSku);
}

private void OnPurchaseInitiatedForProduct(Product product)
{
        // Use this method to disable any purchases UI button or to show a loading
}

private void OnPurchaseFinishedForProduct(Product product)
{
        // Use this method to enable any purchases UI button or to hide a loading
}

private void OnPurchaseSuccessForProduct(Product product)
{
    // Product has been successfully purchased
}

private void OnPurchaseFailedWithError(Error error, Product product)
{
    // Purchase failed
}

Restoring Purchases

If you want to manually trigger a purchases restore, call HomaStore.RestorePurchases. You can gather each product status on the callback OnPurchasesRestored or just get the updated product with HomaStore.GetProduct once the restore has completed.

⚠️ Android does an automatic purchases restore upon first game run while iOS require to be done by user input (usually a button in settings window). See initialization flow above.

public void RestorePurchases()
{
    HomaStore.OnPurchasesRestored += OnPurchasesRestored;
    HomaStore.RestorePurchases();
}

private void OnPurchasesRestored(Product[] products)
{
    // The products list will contain all products (purchased and not purchased)
    // with their statuses updated. From now on, by querying HomaStore.GetProduct()
    // you will also get the latest and updated status of each product

        // Use Product.PurchaseActive to check which products have been purchased 
        // by the user
}

Determining if a purchase (or subscription) is active

Whenever you have access to an instance of HomaGames.HomaBelly.IAP.Product, either after a purchase restore, a successful purchase or just a product fetch, you will be able to determine if that product has been already purchased:

  • PurchaseActive for consumable and non-consumable items
  • SubscriptionInfo if the item is a subscription, which IsSubscribed property will inform if the subscription is active

For example:

public void UpdatePurchaseStatus(Product product)
{
    string purchaseStatus = "";
    switch (product.Type)
    {
        case ProductType.CONSUMABLE:
        case ProductType.NON_CONSUMABLE:
            purchaseStatus = product.PurchaseActive ? "Purchase active" : "Not purchased";
            break;

        case ProductType.SUBSCRIPTION:
            purchaseStatus = product.SubscriptionInfo.IsSubscribed ? "Active" : "Not active";
            break;
    }

        // Update your UI accordingly
}

Request/purchase Dynamic Products

⚠️ Starting with Homa Belly Purchases v1.4.0

Homa Belly Purchases allows you to interact, fetch and purchase products defined in Google Play/Apple Store but not present in Homa Belly Purchases Catalog. This allows you to create/offfer new IAPs without needing to push a new build to the stores.

The most common use case for this is N-Testing different SKUs in your game to determine which converts better. You can obtain a SKU from N-Testing and invoke HomaStore.AddDynamicProductsToCatalog to make this product available to purchase through HomaStore. You will be notified at OnProductsRetrieved once the product is available to be used.

Code sample (refer to PurchaseDemo.cs for more details):

namespace HomaGames
{
    public class PurchaseDemo : MonoBehaviour
    {
        private void Start()
        {
            // Initialize
            HomaStore.OnProductsRetrieved += OnProductsRetrieved;
            HomaStore.Initialize();
        }

        private void OnProductsRetrieved(Product[] products)
        {
                        // Ready to use the newly fetched Dynamic SKUs
        }

        public void FetchNewProducts()
        {
            HomaStore.AddDynamicProductsToCatalog(
#if UNITY_ANDROID
                new ProductSimpleDefinition("com.damysus.iap.test.subscriptiontwo:weekly", ProductType.SUBSCRIPTION),
                new ProductSimpleDefinition("com.homagames.purchases.default.android.consumable", ProductType.CONSUMABLE),
                new ProductSimpleDefinition("damysus.iap.test.nonconsumable001", ProductType.NON_CONSUMABLE)
#elif UNITY_IOS
                new ProductSimpleDefinition("com.damysus.iap.test.subscriptiontwo", ProductType.SUBSCRIPTION),
                new ProductSimpleDefinition("damysus.iap.test.notinrevcat", ProductType.CONSUMABLE),
                new ProductSimpleDefinition("com.damysus.iap.test.noads", ProductType.NON_CONSUMABLE)
#endif
            );
        }
    }
}

Upgrade/downgrade Subscriptions

⚠️ Starting with Homa Belly Purchases v1.4.0

Now you can upgrade/downgrade (update) subscriptions for users already subscribed to any product. Invoke HomaStore.UpdateSubscription with oldProductId (the current subscription) and newProductId (the new subscription)

Code sample (refer to PurchaseDemo.cs for more details):

namespace HomaGames
{
    public class PurchaseDemo : MonoBehaviour
    {
        private void Start()
        {
            // Initialize
            HomaStore.OnSubscriptionUpdateSuccessWithProduct += product =>
            {
                UnityEngine.Debug.Log($"[Purchase Demo] Subscription updated successfully to {product?.Id}");
            };
            HomaStore.OnSubscriptionUpdateFailedWithError += (error, product) =>
            {
                UnityEngine.Debug.Log($"[Purchase Demo] Subscription update failure: {error?.ErrorMessage}");
            };
            
            HomaStore.Initialize();
        }

        public void UpdateSubscription()
        {
        #if UNITY_ANDROID
            HomaStore.UpdateSubscription("com.homagames.default.subscription.android:weekly", "com.homagames.purchases.default.android.subscription:montly");
        #else
            HomaStore.UpdateSubscription("com.damysus.iap.test.subscriptionone", "com.damysus.iap.test.subscriptiontwo");
        #endif
        }
    }
}


Best Practices

Sometimes your players may face situations where Products are not available (ie: unstable connectivity, uncertain errors, etc...), leading them to unsuccessful purchases.

Here are a few best practices we encourage you to implement to avoid players frustration and ensure a smooth experience:

  1. Always check the Product to be purchased is available. If Product is not available, disable your IAP button so players are aware the purchase is not available. This will avoid frustration for thos players willing to purchase and ending in a unsuccessful purchase

  2. If a Product is not available for any reason, as a retry attempt, you can invoke HomaStore.AddDynamicProductsToCatalog method with the IAP sku and type.

    1. This method will try to fetch the Product from servers and will invoke OnStoreProductsRetrieved once more if fetched successfull

    2. Listen OnStoreProductsRetrieved and check for the Product availability once more. If available, enable the button for the user



API Reference