Adding AppCoins alongside Unity IAP v4 or earlier
This guide covers adding AppCoins Billing to a Unity game that uses Unity IAP v4 or earlier. The AppCoins plugin requires Unity IAP v5 — you need to upgrade first. The Unity IAP v4→v5 upgrade changes how purchase completion works, which affects your existing code before AppCoins enters the picture.
If your project is already on Unity IAP v5 or later, see Adding AppCoins alongside Unity IAP v5 instead.
Step 1: Upgrade Unity IAP to v5
Open Window → Package Manager, find In App Purchasing, and upgrade to 5.0 or later.
Step 2: Apply Unity IAP v5 API Changes
Unity IAP v5 replaced the IStoreListener callback interface with event subscriptions on IStoreController. The purchase-completion pattern changed most significantly — ProcessPurchase is gone.
Purchase completion
Before (v4):
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
{
GiveItemToUser(args.purchasedProduct.definition.id);
return PurchaseProcessingResult.Complete;
}
After (v5):
// Subscribe in your initialization code
_controller.OnPurchasePending += OnPurchasePending;
private void OnPurchasePending(PendingOrder order)
{
var product = order.CartOrdered.Items().FirstOrDefault()?.Product;
if (product != null) GiveItemToUser(product.definition.id);
_controller.ConfirmPurchase(order); // replaces returning PurchaseProcessingResult.Complete
}
Store initialization
Before (v4):
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
_controller = controller;
foreach (var product in controller.products.all)
Debug.Log(product.definition.id);
}
After (v5):
// Subscribe before Connect()
_controller.OnProductsFetched += OnProductsFetched;
private void OnProductsFetched(List<Product> products)
{
foreach (var product in products)
Debug.Log(product.definition.id);
}
Initialization failure
Before (v4):
public void OnInitializeFailed(InitializationFailureReason error) { }
public void OnInitializeFailed(InitializationFailureReason error, string message) { }
After (v5):
_controller.OnStoreDisconnected += failure =>
Debug.LogError($"Store connection failed: {failure.Message}");
Purchase failure
Before (v4):
public void OnPurchaseFailed(Product product, PurchaseFailureReason reason) { }
After (v5):
_controller.OnPurchaseFailed += OnPurchaseFailed;
private void OnPurchaseFailed(FailedOrder order)
{
Debug.LogError($"Purchase failed: {order.FailureReason}");
}
IStoreListener is no longer needed
Once you have migrated to the event-subscription pattern, your class does not need to implement IStoreListener. Remove the interface declaration and any remaining stub methods.
Initializing the store
Before (v4):
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.AddProduct("gas", ProductType.Consumable);
UnityPurchasing.Initialize(this, builder); // synchronous, IStoreListener callback
After (v5):
_controller = UnityIAPServices.StoreController();
_controller.OnProductsFetched += OnProductsFetched;
_controller.OnPurchasePending += OnPurchasePending;
await _controller.Connect();
// Replaces builder.AddProduct — define product definitions and fetch after Connect
_controller.FetchProducts(new List<ProductDefinition>
{
new ProductDefinition("gas", ProductType.Consumable)
});
Step 3: Add the AppCoins Plugin
Download the latest .unitypackage from the GitHub releases page and import it:
- In Unity, go to Assets → Import Package → Custom Package...
- Select the downloaded
.unitypackagefile. - In the Import Unity Package dialog, ensure all items are selected and click Import.
The plugin files will appear under Assets/Plugins/iOS/AppCoinsSDKPlugin/.
Step 4: Add AppCoins
Once the project compiles cleanly on Unity IAP v5, adding AppCoins is one line. Before your Connect() call, add:
using AppCoins.Unity;
// Add this before Connect()
await AppCoinsIAP.ConfigureStoreAsync(AppCoinsStoreMode.Automatic);
await _controller.Connect();
AppCoinsStoreMode.Automatic activates AppCoins Billing on qualifying installs and falls back to Apple Billing otherwise — see How Runtime Detection Works. No other code changes are needed.
Before / After Full Example
Before — Unity IAP v4:
using UnityEngine;
using UnityEngine.Purchasing;
public class IAPManager : MonoBehaviour, IStoreListener
{
private IStoreController _controller;
void Start()
{
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
builder.AddProduct("gas", ProductType.Consumable);
UnityPurchasing.Initialize(this, builder);
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
_controller = controller;
}
public void OnInitializeFailed(InitializationFailureReason error) { }
public void BuyProduct(string productId)
{
_controller.InitiatePurchase(productId);
}
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
{
GiveItemToUser(args.purchasedProduct.definition.id);
return PurchaseProcessingResult.Complete;
}
public void OnPurchaseFailed(Product product, PurchaseFailureReason reason)
{
Debug.LogError($"Purchase failed: {reason}");
}
private void GiveItemToUser(string productId)
{
Debug.Log($"Delivering: {productId}");
}
}
After — Unity IAP v5 with AppCoins:
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Purchasing;
using AppCoins.Unity;
public class IAPManager : MonoBehaviour
{
private StoreController _controller;
private readonly List<ProductDefinition> _products = new List<ProductDefinition>
{
new ProductDefinition("gas", ProductType.Consumable)
};
private async void Start()
{
// AppCoins: configure before Connect
await AppCoinsIAP.ConfigureStoreAsync(AppCoinsStoreMode.Automatic);
_controller = UnityIAPServices.StoreController();
_controller.OnProductsFetched += OnProductsFetched;
_controller.OnPurchasePending += OnPurchasePending;
_controller.OnPurchaseFailed += OnPurchaseFailed;
// Re-fire OnPurchasePending for any unfinished purchases found by FetchPurchases()
_controller.ProcessPendingOrdersOnPurchasesFetched(true);
await _controller.Connect();
// Fetch product metadata (replaces builder.AddProduct + UnityPurchasing.Initialize)
_controller.FetchProducts(_products);
// Trigger recovery of unfinished purchases — results arrive via OnPurchasePending
_controller.FetchPurchases();
}
private void OnProductsFetched(List<Product> products)
{
foreach (var product in products)
Debug.Log($"{product.definition.id}: {product.metadata.localizedPriceString}");
}
public void BuyProduct(string productId)
{
_controller.PurchaseProduct(productId);
}
private void OnPurchasePending(PendingOrder order)
{
var product = order.CartOrdered.Items().FirstOrDefault()?.Product;
if (product == null) return;
GiveItemToUser(product.definition.id);
_controller.ConfirmPurchase(order);
}
private void OnPurchaseFailed(FailedOrder order)
{
Debug.LogError($"Purchase failed: {order.FailureReason}");
}
private void GiveItemToUser(string productId)
{
Debug.Log($"Delivering: {productId}");
}
}
The key changes from v4 to the final result:
IStoreListenerremoved — no more interface to implementUnityPurchasing.Initialize(this, builder)→await _controller.Connect()+_controller.FetchProducts(products)ProcessPurchase→OnPurchasePending+controller.ConfirmPurchase(order)OnInitialized→OnProductsFetchedevent subscriptionawait AppCoinsIAP.ConfigureStoreAsync(AppCoinsStoreMode.Automatic)added beforeConnect()