Unity SDK Integration Documentation

Overview

In order to provide a better and simplified integration of the Billing SDK for the Unity developers, the Aptoide Billing SDK Unity was created. It consists in a Package to be imported by the Unity projects which contains mirrored classes and methods of the Aptoide Billing SDK Native. It provides methods to initialize the Native SDK, manage billing operations, and handle callbacks from the native SDK. This Package is designed to simplify the integration of in-app purchases and billing-related features in Unity applications.
This guide helps to integrate this Aptoide Billing SDK Unity Package.


Import and usage in Unity

Import through Unity Package Manager

  1. Open the top menu bar: Window > Package Manager.
  2. Click the + sign and select Import via git URL.
  3. Paste the following link:
    https://github.com/Catappult/appcoins-sdk-unity.git
    Check the available Releases in here to know our latest updates.

Files Imported

Runtime/Plugins/Android

The files in this folder must be manually imported into the Assets/Plugins/Android folder in your project.

IMPORTANT
After copying them to the Assets/Plugins/Android folder, remove the Runtime/Plugins/Android folder from the Package imported to avoid Plugin collision.

baseProjectTemplate.gradle

This file serves the purpose to identify the repositories and sources for dependencies.
If you don't already have a build.gradle file in your project, you can use the template baseProjectTemplate.gradle.

gradleTemplate.properties

This file has the necessary options to use the AppCoins Billing Native SDK.
If you don't have already a gradle.properties file in your project, you can use the template gradleTemplate.properties.

mainTemplate.gradle

This file includes the necessary dependencies to use the Unity Billing SDK.
If you don't already have a main.gradle file in your project, you can use the template mainTemplate.gradle.

If you already have the file for dependencies management, simply add the 2 dependencies used by the Unity Billing SDK.

dependencies {
    implementation("io.catappult:android-appcoins-billing:0.9.0.8") // Check the version in the mainTemplate.gradle to avoid any failures with the Native Billing SDK versioning
    implementation("org.json:json:20210307")
} 
AptoideBillingSDKUnityBridge.java

This is file serves as the Main bridge between the Unity Billing SDK and the Android Native Billing SDK.
It connects the Unity to the Native SDK by calling the methods in the AppcoinsBillingClient class.

Runtime/SDK

AptoideBillingSDKManager.cs

This class is used to make the calls from your Project to the Unity Billing SDK. It has the mirrored methods of the Native Billing SDK.


Features in the Unity Billing SDK

Initialization

  • Initializes the Aptoide Billing SDK with the required parameters.
  • Establishes a connection to the native billing service.

Billing Operations

  • Query SKU details asynchronously.
  • Launch the billing flow for in-app purchases.
  • Consume purchased items.
  • Query purchases made by the user.
  • Check if specific features are supported by the SDK.

App Update Management

  • Check if an app update is available.
  • Launch dialogs or redirect users to the store for updates.

Callback Handling

  • Handles callbacks from the native SDK for billing setup, purchase updates, SKU details, and consumption responses.

Integration Notes

To use the AptoideBillingSDKManager, you must create a separate class to invoke the methods in it and also apply the game logic needed.


Example Billing Flow

  1. Initialize the SDK using InitializePlugin.
  2. Query completed, but non-consumed Purchases using QueryPurchases to consume them.
  3. Query available SKUs using QuerySkuDetailsAsync to present the correct prices to the Users.
  4. Launch the billing flow for a selected SKU using LaunchBillingFlow.
  5. Handle the result of the Purchase received in the method OnPurchasesUpdated of IPurchasesUpdatedListener.
  6. Validate the purchase on the server side.
  7. Deliver the Item to the User.
  8. Consume the purchase using ConsumeAsync to notify that the Process of Purchase and Delivery has been successfully completed on your side.

Implementation Guide

1. Service connection and Initialization

Once the Unity Package is fully integrated you need to initialize the AptoideBillingSDKManager.
To do this, you need to first implement the listeners used in the AptoideBillingSDKManager. You can do this by implementing the listeners in variables, or by directly in your Game Logic class, like this:

public class Logic : MonoBehaviour,
                    IAppCoinsBillingStateListener,
                    IConsumeResponseListener,
                    IPurchasesUpdatedListener,
                    ISkuDetailsResponseListener
{
...
    void Start() {
        AptoideBillingSDKManager.InitializePlugin(
            this,
            this,
            this,
            this,
            "YOUR_PUBLIC_KEY", // Set here the public Key associated to your Billing Integration
            gameObject.name
        );
    }
...
}

To get the Public Key, follow this documentation.

Once you've made the initialization, you will receive the connection state to the Billing Service in the OnBillingSetupFinished and OnBillingServiceDisconnected methods.
When the connection is successful, you will receive a call in the OnBillingSetupFinished with responseCode 0 and call the necessary methods:

public void OnBillingSetupFinished(int responseCode)
{
    if (responseCode == 0)
    {
        // Check pending purchases of Consumables
        CheckPendingConsumables();


        // Check for pending and active Subscriptions
        CheckSubscriptions();

        // Query in-app sku details
        QueryInapps()

        // Query subscriptions sku details
        QuerySubs()
    }
    else
    {
        Debug.LogError($"Billing setup failed with response code: {responseCode}");
    }
}

2. Query non-consumed Purchases and active Subscriptions

When the setup finishes successfully you should immediately check for pending purchases of Consumables and the active or pending Subscriptions. If there are pending purchases you should verify their legitimacy, deliver the Item to the User and consume them. The consumption will be explained in step 5.

Consumables
The example below shows how to check for pending Purchases of Consumables:

public void CheckPendingConsumables()
{
    // Query purchases for inapp products
    PurchasesResult inAppPurchasesResult = AptoideBillingSDKManager.QueryPurchases("inapp");
    HandlePurchasesResult(inAppPurchasesResult);

    // Validate the Purchase in a server-to-server request
    // follow this page https://docs.catappult.io/docs/iap-validators-server-to-server-check-client

    // After validating, deliver the product to the User

    // Lastly AptoideBillingSDKManager.ConsumeAsync should be called to notify 
    // Aptoide Services of the Successfull delivery and allow the User to Purchase once again the Item
}

Subscriptions
To verify the active/pending Subscriptions, use the QueryPurchases method. The result consists of Pending Subscriptions (to be consumed) and Active ones. To correctly remove from the User the Subscriptions that were expired, you should match the ones missing in the result received that are currently available to the User.

The example below shows how to check for Subscriptions:

public void CheckSubscriptions()
{
    // Query purchases for subscription products
    PurchasesResult subsPurchasesResult = AptoideBillingSDKManager.QueryPurchases("subs");
    HandlePurchasesResult(subsPurchasesResult);

    // Validate the Purchase in a server-to-server request
    // follow this page https://docs.catappult.io/docs/iap-validators-server-to-server-check-client

    // After validating, deliver the product to the User

    // Lastly AptoideBillingSDKManager.ConsumeAsync should be called to notify 
    // Aptoide Services of the Successfull delivery and allow the User to Purchase once again the Item

    // Remove Subscriptions from the User when not present in this list
}

📘

Note

To give real-time information to the User about the status of it's Subscriptions, use the RTDN's.

3. Querying Products

After starting the connection, you should query for the products available to buy in order to display them to the user with the correct pricing from the Aptoide Connect. This query includes not only the product's title but also the description, price, etc...
To query the products you can use the AptoideBillingSDKManager.QuerySkuDetailsAsync which will give the result to the to process Aptoide Connect's response.

After the listener is created, you can pass it to the querySkuDetailsAsync together with the parameters as shown below:

private static string[] inappSkus = new string[] { "attempts" };
private static string[] subsSkus = new string[] { "golden_dice" };

public void QueryInapps()
{
    // inappSkus is a list of in-app product IDs
    AptoideBillingSDKManager.QuerySkuDetailsAsync(inappSkus, "inapp");
}

public void QuerySubs()
{
    // Check if subscriptions are supported
    if (AptoideBillingSDKManager.IsFeatureSupported("SUBSCRIPTIONS") == 0)
    {
        Debug.Log("Subscriptions are supported.");
        // subsSkus is a list of subscription product IDs
        AptoideBillingSDKManager.QuerySkuDetailsAsync(subsSkus, "subs");
    }
    else
    {
        Debug.LogWarning("Subscriptions are not supported by the Billing Service.");
    }
}

public void OnSkuDetailsResponse(int responseCode, SkuDetails[] skuDetailsList)
{
    if (responseCode == 0)
    {
        foreach (var skuDetails in skuDetailsList)
        {
            // Apply the SKU details to the UI or perform any action
            // based on the SKU type (inapp or subs)
        }
    }
    else
    {
        Debug.LogError($"Failed to receive SKU details. Response code: {responseCode}");
    }
}

4. Launching the Billing Flow

To start a purchase flow use the function AptoideBillingSDKManager.LaunchBillingFlow. This takes the SKU (sku), the type of the SKU (inapp or subs) and data to be used by the developer. The following snippet shows a possible function to be associated with the "buy" button:

public void StartPurchase(string sku, string skuType) {
    if (AptoideBillingSDKManager.IsReady()) {

        // Verify if the purchase of Subscription type you are making is a Free Trial or not
        bool isFreeTrial = IsFreeTrialSubscription(sku, skuType, obfuscatedAccountId);
          
        int response = AptoideBillingSDKManager.LaunchBillingFlow(
            sku, 
            skuType, 
            "user_123", // Developer payload to be used as a way of indentifying the Purchase on your side
          	"user_123", // Obfuscated Account ID to identify the User in an Application perspective
          	isFreeTrial
        );
    }
}

Use the obfuscatedAccountId parameter to help prevent fraud and abuse of the billing system. This identifier allows us to accurately associate billing activity with a specific user from your application, enhancing security and reliability. This parameter can be null if there is no User account logic.

Launching a Free Trial

To enable a Free Trial for a user, set the freeTrial parameter of the true in the LaunchBillingFlow method. This will initiate a Free Trial payment based on the provided obfuscatedAccountId.

Note: The obfuscatedAccountId is required when launching a Free Trial payment.

If the user has already consumed a Free Trial for the subscription, any subsequent subscription attempt will automatically fall back to a regular payment flow. This ensures a smooth payment experience and allows you to safely set freeTrial to true by default without causing errors.

public Boolean IsFreeTrialSubscription(string sku, string skuType, string obfuscatedAccountId)
{
    // First verify if the features Free Trial and Obfucasted Account Id are available
    if (AptoideBillingSDKManager.IsFeatureSupported(2) != 0)
    {
        return false;
    }

    if (AptoideBillingSDKManager.IsFeatureSupported(1) != 0)
    {
        return false;
    }

    // Verify if the Sku Type is a Subscription
    if (skuType != "subs")
    {
        return false;
    }

    // Apply your internal App Logic to verify if the User should receive a Free Trial or not
    /* Example:
        return obfuscatedAccountId == "123" && sku == "trial_dice";
    */

    return false
}

5. Process the purchase and give the item to User

public void OnPurchasesUpdated(int responseCode, Purchase[] purchases)
{
    if (responseCode == 0)
    {
        foreach (var purchase in purchases)
        {
            string token = purchase.purchaseToken;
            // Validate the Purchase in a server-to-server request
            // follow this page https://docs.catappult.io/docs/iap-validators-server-to-server-check-client

            // After validating, deliver the product to the User

            // Lastly ConsumeAsync should be called to allow the user to purchase the 
            // item again and change the purchase's state.
            // Also consume subscriptions to make them active, there will be no issue in consuming more than once
            AptoideBillingSDKManager.ConsumeAsync(token);
        }
    }
    else
    {
        // Handle the error
        Debug.Log("Error: " + responseCode);
    }
}

Validate the Purchase

To ensure the legitimacy of the Purchases and prevent fraud, your application should always verify the Purchases in a server-to-server request. To make this verification follow the guidelines in the In-App Purchase Validation page. Only after validating successfully the Purchase you should proceed by delivering the Product to the User.

Consume a purchase

After the purchase is completed, it needs to be consumed. To consume a purchase, use the function AptoideBillingSDKManager.ConsumeAsync. The result of the Consume will be retrieved to the OnConsumeResponse method.

Note that, if you do not consume the purchase within 48 hours, it will automatically be refunded.

Below you can find an example of the OnConsumeResponse implementation:

public void OnConsumeResponse(int responseCode, string purchaseToken)
{
    if (responseCode == 0)
    {
        Debug.Log($"Purchase with token {purchaseToken} consumed successfully.");
    }
    else
    {
        Debug.LogError($"Failed to consume purchase with token {purchaseToken}. Response code: {responseCode}");
    }
}

Troubleshooting

Common Issues

  1. Billing not initializing:

    • Check internet connectivity
  2. Purchases not completing:

    • Ensure correct public key
  3. Validation failures:

    • Verify server endpoint
    • Check purchase token validity

Best Practices

  • Always validate purchases server-side
  • Implement proper error handling
  • Test thoroughly in sandbox environment

FAQ

What is the recommended Unity version?

The most suitable Unity version for integration is 2021.3.8f1.

Is there any example that I can follow for the Unity integration?

Yes, there is the AppCoins Unity Diceroll which integrates the Unity Billing SDK. Use it to clarify any existing doubts.

How can I get more information about the integration process based on the Native Billing SDK?

To get more information about the flow and process of the Native Billing SDK, check our Native Billing SDK Integration guide. It contains all the necessary information to have a successful integration. Following it, you can call the mirrored methods from the AptoideBillingSDKManager.cs class and get the same result.