How to Setup IAP

Use this guide to add or configure an in-app purchase product. Based directly on the project's IAPManager, which uses the current Unity IAP v5 API (UnityIAPServices.StoreController(), package com.unity.purchasing 5.4.2, backed by Unity.Services.Core).

Architecture Context

  • IAPManager.Initialize() first calls UnityServices.InitializeAsync() with the environment name hardcoded to "production" — this codebase always talks to the real store backends, even from the Editor or a debug build; there's no separate sandbox environment switch here.
  • Products are not hardcoded in IAPManager. They're data-driven from ShopProductIAPConfig ScriptableObject assets (under Resources/ShopProductConfigs/IAP/), each carrying:
    • ID — the store product ID. Must exactly match the product ID you registered in App Store Connect / Google Play Console, including case.
    • Type — Unity IAP's own ProductType enum (Consumable, NonConsumable, Subscription). Must match what you registered on the store.
    • Info, ProductType (the game's own ShopProductType enum — NoAds / ResourcesForAds / ResourcesRealMoney), and Reward (a resource type + amount) — these only matter to the game's own shop logic; the store doesn't see or care about them.
  • GameConfig._shopProductIAPConfigs is a serialized array wired in the Inspector — GameConfig builds it into a ShopProductsIAPMap dictionary keyed by ID at startup, and that dictionary is exactly what IAPManager.InitializePurchasing() reads to build the ProductDefinition list it fetches from the store. A ShopProductIAPConfig asset that exists but isn't in this array is invisible to purchasing.
  • IAPManager.GetPrice(productID) returns the store's own localized price string, populated once OnProductsFetched has run — prices are never hardcoded.
  • RestorePurchases() only runs an explicit restore flow on RuntimePlatform.IPhonePlayer (iOS); on other platforms it logs and no-ops, since Android purchases are restored automatically via FetchPurchases() / OnPurchasesFetched at init.

Pre-Setup Checklist

  • A Unity Gaming Services project with In-App Purchasing enabled.
  • Store-side setup done first: App Store Connect (iOS) and/or Google Play Console (Android) apps created, with the relevant banking/agreements in place — purchases can't complete without this, independent of any code change.
  • com.unity.purchasing (5.4.2) installed via the Package Manager.

Main Procedure

Step 1: Create the Product on the Store First

In App Store Connect / Google Play Console, create the in-app product or subscription and note its exact product ID (reverse-DNS style, e.g. com.yourcompany.yourgame.yourproduct) and whether it's Consumable, Non-Consumable, or a Subscription.

Step 2: Create a Matching ShopProductIAPConfig Asset

In the Project window under Resources/ShopProductConfigs/IAP/, use Create → Config → ShopProductIAPConfig and set:

  • ID — the exact store product ID from Step 1.
  • Type — the matching Unity IAP ProductType — must agree with what you registered on the store.
  • Info / ProductType (game's own enum) / Reward — whatever your game's shop logic needs; these are internal to the game only.

Step 3: Register the Asset

Drag the new asset into GameConfig's _shopProductIAPConfigs array in the Inspector. This step is easy to miss — an asset that exists on disk but isn't in this array is never fetched.

Step 4: Wire the Purchase Button

Call IAPManager.OnPurchaseClicked(productID) with the same ID string used in Step 2. Listen to ON_PRODUCT_PURCHASED, ON_PURCHASE_FAILED, and ON_PURCHASE_PROCESS_COMPLETE to react to the result.

Step 5: Display the Price

Call IAPManager.GetPrice(productID) once products have been fetched — don't show a shop screen before that, since it returns "0" until then.

Common Edit Recipes

Recipe A: Add a New Product

Steps 1–3 above, in order. No code changes are required — IAPManager automatically picks up anything present in GameConfig.ShopProductsIAPMap at init.

Recipe B: Change What a Product Rewards, Without Touching the Store

Edit the Reward / ProductType (game's own enum) fields on the existing ShopProductIAPConfig asset. The store-side ID and Type stay untouched, since the store has no concept of in-game rewards.

Troubleshooting

  • OnProductsFetchFailed, or a product never fetches. The ID on the config asset doesn't exactly match the store product ID (check case), or the store-side product isn't yet in an approved/ready state.
  • GetPrice() keeps returning "0". Called before OnProductsFetched has completed — gate your shop UI on that instead of assuming prices are available immediately after Initialize().
  • Purchase button does nothing, logs "Not initialized". The store controller hasn't connected yet, or OnStoreDisconnected fired — check _controller.GetConnectionState() before allowing purchase attempts.
  • New store product added, nothing happens in-game. Check it was actually dragged into GameConfig._shopProductIAPConfigs (Step 3) — a store product with no matching config asset in that array is never seen by IAPManager.
  • Restore Purchases seems to do nothing on Android. Expected — RestorePurchases() only runs an explicit flow on iOS; Android restores automatically at init via FetchPurchases().