This is a beginner step-by-step guide that will show you how to set up the Google Play Store alongside Unity IAP to allow your application to purchase consumable and non-consumable products.
This guide will assume you have already uploaded your application's App Bundle and can access the Monetization functions. If not, you can view it here. (link to KBA). The following was completed using Unity Version 6.000.2.8f1 and IAP version 5.0.2
Prerequisites
- Google Play Developer Account
- Access to Monetization features
Google Play Console
Set Up Products in the Console
- Go to Google Play Console
- Go to the Google Play Console and create an App, this can be an app or a game
- In your app’s dashboard, go to Monetize> Products > In-app products.
- Add your products (managed products or subscriptions).
- If you haven’t done so already, it will prompt you to add your APK file
- Set the ID, name and description of the products and then activate them
- For this example I have made 3 consumable products, 10Coins, 100Coins, 1000Coins (non consumables act in the same way)
- Note the Product IDs. These must match the IDs you use in your Unity IAP configuration
Set up Testers
In your Google Play Console :
- Go to Settings -> Email Lists -> Create Email List
- Add the emails of users you want to be able to test the purchases on
Adding your Google Licence Key to Unity
In your Google Play Console :
- Select the app for which you need the license key
- Go to the Monetize menu in the left-hand navigation
- Click on Monetization setup.
- Copy the Base-64 encoded key under Licencing and copy it.
Sign into the Unity Cloud Dashboard.
- Create a project and with the permissions set as 'Owner'
- Under Projects, Select project->settings->Google Licence key
- Paste key you copied from the Google Play Console.
Unity Editor
Set up Unity IAP in your project
- Open your Unity project.
- Go to Window > Package Manager.
- Select Unity Registry
- Search for "In-App Purchasing" and install it
Connect to Unity Cloud Dashboard
- In Unity Editor, select Edit > Project Settings > Services.
- Link your project.
- Select Use an existing Unity project ID.
- Select the organization and project from the dropdown menus that you entered your Google Key earlier.
- Select Link project ID.
UI setup
- Add a canvas to a scene
- Add a Panel UI object as a child of the Canvas which we will use as our shop window
- Add Buttons for your products
- Add a text field to show our updated values
(We will be using TextMeshPro for both the text and our buttons in this example)
Coded IAP
- Create an IAP Manager Script
- Add the following Code
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.UI;
using TMPro;
public class IAPManager : MonoBehaviour
{
StoreController m_StoreController;
// Start is called once before the first execution of Update after the MonoBehaviour is created
public string thousandCoinProductId = "1000_coins";
public string hundredCoinProductId = "100_coins";
public string tenCoinProductId = "10_coins";
[SerializeField] public TMP_Text TotalCoinsText;
int CoinCount = 0;
private void Start()
{
InitializeIAP();
}
async void InitializeIAP()
{
m_StoreController = UnityIAPServices.StoreController();
m_StoreController.OnPurchasePending += OnPurchasePending;
m_StoreController.OnPurchaseConfirmed += OnPurchaseConfirmed;
m_StoreController.OnPurchaseFailed += OnPurchaseFailed;
m_StoreController.OnStoreDisconnected += OnStoreDisconnected;
Debug.Log("Connecting to store.");
await m_StoreController.Connect();
m_StoreController.OnProductsFetchFailed += OnProductsFetchedFailed;
m_StoreController.OnProductsFetched += OnProductsFetched;
FetchProducts();
}
void FetchProducts()
{
var initialProductsToFetch = new List<ProductDefinition>
{
new(thousandCoinProductId, ProductType.Consumable),
new(hundredCoinProductId, ProductType.Consumable),
new(tenCoinProductId, ProductType.Consumable)
};
m_StoreController.FetchProducts(initialProductsToFetch);
}
public void BuyTenGold()
{
m_StoreController.PurchaseProduct(tenCoinProductId);
}
public void BuyHundredGold()
{
m_StoreController.PurchaseProduct(hundredCoinProductId);
}
public void BuyThousandGold()
{
m_StoreController.PurchaseProduct(thousandCoinProductId);
}
void OnPurchaseFailed(FailedOrder order)
{
var product = GetFirstProductInOrder(order);
if (product == null)
{
Debug.Log("Could not find product in failed order.");
}
Debug.Log($"Purchase failed - Product: '{product?.definition.id}'," +
$"PurchaseFailureReason: {order.FailureReason.ToString()},"
+ $"Purchase Failure Details: {order.Details}");
}
void OnPurchasePending(PendingOrder order)
{
var product = GetFirstProductInOrder(order);
if (product is null)
{
Debug.Log("Could not find product in order.");
return;
}
//Add the purchased product to the players inventory
if (product.definition.id == tenCoinProductId)
{
AddCoin(10);
}
else if (product.definition.id == hundredCoinProductId)
{
AddCoin(100);
}
else if (product.definition.id == thousandCoinProductId)
{
AddCoin(1000);
}
Debug.Log($"Purchase complete - Product: {product.definition.id}");
m_StoreController.ConfirmPurchase(order);
}
void OnPurchaseConfirmed(Order order)
{
switch (order)
{
case ConfirmedOrder confirmedOrder:
OnPurchaseConfirmed(confirmedOrder);
break;
case FailedOrder failedOrder:
OnPurchaseConfirmationFailed(failedOrder);
break;
default:
Debug.Log("Unknown OnPurchaseConfirmed result.");
break;
}
}
void OnPurchaseConfirmed(ConfirmedOrder order)
{
var product = GetFirstProductInOrder(order);
if (product == null)
{
Debug.Log("Could not find product in purchase confirmation.");
}
Debug.Log($"Purchase confirmed- Product: {product?.definition.id}");
}
void OnPurchaseConfirmationFailed(FailedOrder order)
{
var product = GetFirstProductInOrder(order);
if (product == null)
{
Debug.Log("Could not find product in failed confirmation.");
}
Debug.Log($"Confirmation failed - Product: '{product?.definition.id}'," +
$"PurchaseFailureReason: {order.FailureReason.ToString()},"
+ $"Confirmation Failure Details: {order.Details}");
}
Product GetFirstProductInOrder(Order order)
{
return order.CartOrdered.Items().First()?.Product;
}
// Calling StoreController.Connect without a listener on the StoreController.OnStoreDisconnected event will result in warnings.
void OnStoreDisconnected(StoreConnectionFailureDescription description)
{
Debug.Log($"Store disconnected details: {description.message}");
}
// Calling StoreController.Connect without listeners on StoreController.OnProductsFetched and StoreController.OnProductsFetchedFailed will result in warnings.
void OnProductsFetched(List<Product> products)
{
Debug.Log($"Products fetched successfully for {products.Count} products.");
}
void OnProductsFetchedFailed(ProductFetchFailed failure)
{
Debug.Log($"Products fetch failed for {failure.FailedFetchProducts.Count} products: {failure.FailureReason}");
}
void AddCoin(int amount)
{
CoinCount = CoinCount + amount;
UpdateUI();
}
void UpdateUI()
{
Debug.Log ("Your total coins are " + CoinCount);
TotalCoinsText.text = $"Your Gold: {CoinCount}";
}
}
- Attach your Script to your shop panel.
- Save
Testing in Editor
- Run this application inside the editor
- When you click a button you should see a pop up asking if you want to make a purchase for the fake store. Click Buy and your Coin Count Should increase
Testing on a Device
- Open the Project Settings window by going to Edit->Project Settings
- Select Android Settings
- Scroll down to Identification -> Package Name
- Enter your package name in the form of “com.mycompany.mygame” (You can find this in the application dashboard in Google Play Console)
- Make sure the “Override Default Package Name” is checked
- Scroll down to publishing Settings and click on Keystore Manager
- Create a new Keystore and enter your details or select a previously created one
- Under Minify make sure the “Release” checkbox is selected
- You should now be able to test and run it on an Android device