In-App Purchases Integration (Unity Plugin)
The iOS Billing SDK is a straightforward solution for implementing Catappult billing. Its Unity Plugin provides a simple interface for Unity games to communicate with the SDK. It comprises a Billing client that integrates with AppCoins Wallet, enabling you to retrieve your products from Catappult and facilitate the purchase of those items.
In Summary
The billing flow in your application with the Plugin is as follows:
- Add the AppCoins Unity Plugin;
- Query your In-App Products;
- User wants to purchase a product;
- Application starts the purchase and the Plugin handles it, returning the purchase status and validation data on completion;
- Application gives the product to the user.
Requirements
- Unity 2019.4 or later.
- iOS 17.4 or higher.
Step-by-Step Guide
Setup
- Add AppCoins Unity Plugin
In Unity, add the plugin from the latest release available on the repository https://github.com/Catappult/appcoins-sdk-ios-unity-plugin to your Assets folder.
Implementation
Now that you have the Plugin set-up you can start making use of its functionalities.
-
Check AppCoins Billing Availability
The AppCoins Billing will only be available on devices in the European Union with an iOS version equal to or higher than 17.4 and only in applications distributed through the Aptoide iOS App Store. Therefore, before attempting any purchase, you should check if the SDK is available by callingAppCoinsSDK.Instance.IsAvailable()
.var isAvailable = await AppCoinsSDK.Instance.IsAvailable(); if (isAvailable) { // make purchase }
-
Query In-App Products
You should start by getting the In-App Products you want to make available to the user. You can do this by callingProduct.products
.
This method can either return all of your Catappult In-App Products or a specific list.-
AppCoinsSDK.Instance.GetProducts()
Returns all application Catappult In-App Products:
var products = await AppCoinsSDK.Instance.GetProducts();
-
AppCoinsSDK.Instance.GetProducts(skus)
Returns a specific list of Catappult In-App Products:
var products = await AppCoinsSDK.Instance.GetProducts(new string[] { "coins_100", "gas" });
You will only be able to query your In-App Products once your application is reviewed and approved on Aptoide Connect
-
-
Purchase In-App Product
To purchase an In-App Product you must call the functionAppCoinsSDK.Instance.Purchase(sku, payload)
. The Plugin will handle all of the purchase logic for you and it will return you on completion the result of the purchase. This result is an object with the following properties:- State:
string
(AppCoinsSDK.PURCHASE_STATE_SUCCESS
,AppCoinsSDK.PURCHASE_STATE_UNVERIFIED
,AppCoinsSDK.PURCHASE_STATE_USER_CANCELLED
,AppCoinsSDK.PURCHASE_STATE_FAILED
) - Error:
string
- Purchase:
PurchaseData
In case of success the application will verify the transaction’s signature locally. After this verification you should handle its result:
- If the purchase is verified you should consume the item and give it to the user.
- If it is not verified you need to make a decision based on your business logic, you either still consume the item and give it to the user, or otherwise the purchase will not be acknowledged and we will refund the user in 24 hours.
In case of failure you can deal with different types of errors.
You can also pass a Payload to the purchase method in order to associate some sort of information with a specific purchase. You can use this for example to associate a specific user with a Purchase:
gas.purchase(payload: "User123")
.
async public void Purchase() { var purchaseResponse = await AppCoinsSDK.Instance.Purchase("gas", , "User123"); HandlePurchase(purchaseResponse); } async public void HandlePurchase(PurchaseResponse purchaseResponse) { if (purchaseResponse.State == AppCoinsSDK.PURCHASE_STATE_SUCCESS) { var response = await AppCoinsSDK.Instance.ConsumePurchase(purchaseResponse.PurchaseSku); if (response.Success) { Debug.Log("Purchase consumed successfully"); } else { Debug.Log("Error consuming purchase: " + response.Error); } } }
- State:
-
Handle Indirect Purchases
In addition to standard In-App Purchases, the AppCoins SDK supports Indirect In-App Purchases. These are purchases that users do not initiate directly through a Buy action within the application. Common use cases include:
- Purchasing an item directly from a catalog of In-App Products in the Aptoide Store.
- Buying an item through a web link.
Indirect purchases can be initiated through the following link format:
{domain}.iap://wallet.appcoins.io/purchase?product={sku}&payload={payload}
domain
– The Bundle ID of your application.sku
– The SKU of the product to be purchased.payload
– Custom information that can be associated with the purchase, such as user identification.
The
AppCoinsPurchaseManager.OnPurchaseUpdated
Unity Action allows developers to manage these purchases and assign consumables to users. This action continuously streams purchase updates, ensuring real-time transaction synchronization.The event returns a
PurchaseResponse
object, which should be handled in the same way as a standard In-App Purchase.To properly handle purchase updates, define the subscription within a singleton class, ensuring it remains active for the application’s lifecycle. Use the same HandlePurchase method applied to standard purchases.
private void Awake() { // Singleton enforcement if (Instance != null && Instance != this) { Destroy(gameObject); // Destroy duplicate instances return; } Instance = this; DontDestroyOnLoad(gameObject); // Persist across scenes // Subscribe to purchase updates AppCoinsPurchaseManager.OnPurchaseUpdated += HandlePurchase; } // Already defined previously async public void HandlePurchase(PurchaseResponse purchaseResponse) { if (purchaseResponse.State == AppCoinsSDK.PURCHASE_STATE_SUCCESS) { var response = await AppCoinsSDK.Instance.ConsumePurchase(purchaseResponse.PurchaseSku); if (response.Success) { Debug.Log("Purchase consumed successfully"); } else { Debug.Log("Error consuming purchase: " + response.Error); } } }
-
Query Purchases
You can query the user’s purchases by using one of the following methods:-
AppCoinsSDK.Instance.GetAllPurchases()
This method returns all purchases that the user has performed in your application.
var purchases = await AppCoinsSDK.Instance.GetAllPurchases();
-
AppCoinsSDK.Instance.GetLatestPurchase(string sku)
This method returns the latest user purchase for a specific In-App Product.
var latestPurchase = await AppCoinsSDK.Instance.GetLatestPurchase("gas");
-
AppCoinsSDK.Instance.GetUnfinishedPurchases()
This method returns all of the user’s unfinished purchases in the application. An unfinished purchase is any purchase that has neither been acknowledged (verified by the SDK) nor consumed. You can use this method for consuming any unfinished purchases.
var unfinishedPurchases = await AppCoinsSDK.Instance.GetUnfinishedPurchases();
-
Testing
To test the SDK integration during development, you'll need to set the installation source for development builds, simulating that the app is being distributed through Aptoide. This action will enable the SDK's isAvailable
method.
Follow these steps in Xcode:
-
In your target build settings, search for "Marketplaces".
-
Under "Deployment", set the key "Marketplaces" or "Alternative Distribution - Marketplaces" to "com.aptoide.ios.store".
-
In your scheme, go to the "Run" tab, then navigate to the "Options" tab. In the "Distribution" dropdown, select "com.aptoide.ios.store".
For more information, please refer to Apple's official documentation: https://developer.apple.com/documentation/appdistribution/distributing-your-app-on-an-alternative-marketplace#Test-your-app-during-development
Testing Both Billing Systems in One Build
To facilitate testing both Apple Billing and Aptoide Billing within a single build – without the need to generate separate versions of your application – the AppCoins SDK includes a deep link mechanism that toggles the SDK’s isAvailable
method between true
and false
. This allows you to seamlessly switch between testing the AppCoins SDK (when available) and Apple Billing (when unavailable).
To enable or disable the AppCoins SDK, open your device’s browser and enter the following URL:
{domain}.iap://wallet.appcoins.io/default?value={value}
Where:
domain
– The Bundle ID of your application.value
true
→ Enables the AppCoins SDK for testing.false
→ Disables the AppCoins SDK, allowing Apple Billing to be tested instead.
Sandbox
To verify the successful setup of your billing integration, we offer a sandbox environment where you can simulate purchases and ensure that your clients can smoothly purchase your products. Documentation on how to use this environment can be found at: Sandbox
Classes Definition and Properties
The Unity Plugin integration is based on three main classes of objects that handle its logic:
ProductData
ProductData
represents an in-app product.
Properties:
Sku
: String - Unique product identifier. Example: gasTitle
: String - The product display title. Example: Best GasDescription
: String? - The product description. Example: Buy gas to fill the tank.PriceCurrency
: String - The user’s geolocalized currency. Example: EURPriceValue
: String - The value of the product in the specified currency. Example: 0.93PriceLabel
: String - The label of the price displayed to the user. Example: €0.93PriceSymbol
: String - The symbol of the geolocalized currency. Example: €
PurchaseData
PurchaseData
represents an in-app purchase.
Properties:
UID
: String - Unique purchase identifier. Example: catappult.inapp.purchase.ABCDEFGHIJ1234Sku
: String - Unique identifier for the product that was purchased. Example: gasState
: String - The purchase state can be one of three: PENDING, ACKNOWLEDGED, and CONSUMED. Pending purchases are purchases that have neither been verified by the SDK nor have been consumed by the application. Acknowledged purchases are purchases that have been verified by the SDK but have not been consumed yet. Example: CONSUMEDOrderUID
: String - The orderUid associated with the purchase. Example: ZWYXGYZCPWHZDZUK4HPayload
: String - The developer Payload. Example: 707048467.998992Created
: String - The creation date for the purchase. Example: 2023-01-01T10:21:29.014456ZVerification
: PurchaseVerification - The verification data associated with the purchase.
PurchaseVerification
PurchaseVerification
represents an in-app purchase verification data.
Properties:
Type
: String - The type of verification made. Example: GOOGLESignature
: String - The purchase signature. Example: C4x6cr0HJk0KkRqJXUrRAhdANespHEsyx6ajRjbG5G/v3uBzlthkUe8BO7NXH/1Yi/UhS5sk7huA+hB8EbaQK9bwaiV/Z3dISl5jgYqzSEz1c/PFPwVEHZTMrdU07i/q4FD33x0LZIxrv2XYbAcyNVRY3GLJpgzAB8NvKtumbWrbV6XG4gBmYl9w4oUgJLnedii02beKlvmR7suQcqIqlSKA9WEH2s7sCxB5+kYwjQ5oHttmOQENnJXlFRBQrhW89bl18rccF05ur71wNOU6KgMcwppUccvIfXUpDFKhXQs4Ut6c492/GX1+KzbhotDmxSLQb6aw6/l/kzaSxNyjHg==Data
: PurchaseVerificationData - The data associated with the verification of the purchase.
PurchaseVerificationData
PurchaseVerificationData
represents the body of an in-app purchase verification data.
Properties:
OrderId
: String - The orderUid associated with the purchase. Example: 372EXWQFTVMKS6HIPackageName
: String - Bundle ID of the product's application. Example: com.appcoins.trivialdrivesampleProductId
: String - Unique identifier for the product that was purchased. Example: gasPurchaseTime
: Integer - The time the product was purchased. Example: 1583058465823PurchaseToken
: String - The token provided to the user's device when the product was purchased. Example: catappult.inapp.purchase.SZYJ5ZRWUATW5YU2PurchaseState
: Integer - The purchase state of the order. Possible values are: 0 (Purchased) and 1 (Canceled)DeveloperPayload
: String - A developer-specified string that contains supplemental information about an order. Example: myOrderId:12345678
AppCoinsSDK
This class is responsible for general purpose methods.
Updated about 1 month ago