In this guide, we will walk through how to implement the in-game purchase flow for Google Play Store using LootLocker, from initiating a purchase to validating and granting rewards to the player.
Prerequisites
- A LootLocker account
- At least one created game in the LootLocker Web Console
- Google Play Store IAP configured for your game
- A Catalog Listing configured for Google Play Store IAP
- LootLocker SDK integrated into your game
To implement in-app purchases in your game, you need to:
- Initialize Unity's IAP system
- Register your Google Play products in the IAP system
- Handle the purchase flow when users buy items
- Redeem purchases with LootLocker
Overview
Unity's IAP system handles the communication with Google Play Store. To use it, you must:
- Inherit from
IDetailedStoreListenerto receive purchase callbacks - Import the Unity In-App Purchasing package
Step 1: Initialize the IAP System
In your Awake() method, initialize Unity Services and create an IAP configuration builder:
public async void Awake(){ try { var options = new InitializationOptions() .SetEnvironmentName("production"); await UnityServices.InitializeAsync(options); } catch (Exception exception) { Debug.Log(exception); }
// Create a configuration builder specifically for Google Play Store var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance(AppStore.GooglePlay));}Step 2: Register Your Products
For each product you created in Google Play Console, you must register it with the IAP system using AddProduct(). This tells Unity which products are available for purchase.
The AddProduct() method takes two parameters:
- Product ID: The ID you created in Google Play Console (e.g., "com.company.game.coins100")
- Product Type: The type of product -
Consumable(can be purchased multiple times) orNonConsumable(one-time purchase)
// Register a consumable product (can be repurchased)builder.AddProduct("com.company.game.coins100", ProductType.Consumable);builder.AddProduct("com.company.game.coins500", ProductType.Consumable);
// Register a non-consumable product (one-time purchase)builder.AddProduct("com.company.game.premium_pass", ProductType.NonConsumable);Replace com.company.game.coins100 with your actual product IDs from Google Play Console.
Step 3: Initialize the Purchasing System
After configuring all your products, initialize the IAP system:
UnityPurchasing.Initialize(this, builder);This call registers your IDetailedStoreListener (typically your class implementing the interface) to receive purchase notifications.
Step 4: Handle Purchase Initialization Callback
When the IAP system is ready, OnInitialized() is called. Store the controller for later use:
public void OnInitialized(IStoreController controller, IExtensionProvider extensions){ this.controller = controller; this.extensions = extensions;}Step 5: Trigger a Purchase
When a user clicks a "Buy" button, call InitiatePurchase() with the product ID. First, verify the product exists and is available:
public void Purchase(string productId){ var product = controller.products.WithID(productId);
// Check if the product exists and can be purchased if (product is { availableToPurchase: true }) { controller.InitiatePurchase(product); } else { Debug.Log("Product not available for purchase"); }}Step 6: Handle Purchase Success
When a purchase completes successfully, ProcessPurchase() is called. In this method, send the purchase data to LootLocker for validation and redemption:
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e){ // Extract purchase details string productID = e.purchasedProduct.definition.id; string purchaseToken = e.purchasedProduct.transactionID;
// Send to LootLocker for validation and redemption LootLockerSDKManager.RedeemGooglePlayStorePurchaseForPlayer(productID, purchaseToken, (result) => { if (!result.success) { Debug.Log("Redeem Purchase unsuccessful!"); return; } Debug.Log("Purchase successfully redeemed with LootLocker"); });
return PurchaseProcessingResult.Complete;}Step 7: Handle Purchase Failures
If a purchase fails, OnPurchaseFailed() is called:
public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription){ Debug.Log($"Purchase failed for product {product.definition.id}: {failureDescription.reason}");}Complete Example Script
Complete implementation of the IAP manager
using Unity.Services.Core;using Unity.Services.Core.Environments;using UnityEngine;using UnityEngine.Purchasing;using UnityEngine.Purchasing.Extension;
public class IAPManager : MonoBehaviour, IDetailedStoreListener{ public IStoreController controller; private IExtensionProvider extensions;
public async void Awake() { try { var options = new InitializationOptions() .SetEnvironmentName("production");
await UnityServices.InitializeAsync(options); } catch (Exception exception) { Debug.Log(exception); }
// Create IAP configuration for Google Play Store var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance(AppStore.GooglePlay));
// Register your products (replace with your actual product IDs from Google Play Console) builder.AddProduct("com.company.game.coins100", ProductType.Consumable); builder.AddProduct("com.company.game.coins500", ProductType.Consumable);
// Initialize the purchasing system UnityPurchasing.Initialize(this, builder); }
/// <summary> /// Called when a user clicks the purchase button /// </summary> public void OnPurchaseClicked(string productId) { Purchase(productId); }
/// <summary> /// Initiates a purchase for the given product ID /// </summary> public void Purchase(string productId) { var product = controller.products.WithID(productId);
if (product is { availableToPurchase: true }) { controller.InitiatePurchase(product); } else { Debug.Log($"Product {productId} is not available for purchase"); } }
/// <summary> /// Called when Unity IAP is ready to make purchases /// </summary> public void OnInitialized(IStoreController controller, IExtensionProvider extensions) { this.controller = controller; this.extensions = extensions; }
/// <summary> /// Called when Unity IAP encounters an unrecoverable initialization error /// </summary> public void OnInitializeFailed(InitializationFailureReason error) { Debug.Log($"IAP initialization failed: {error}"); }
/// <summary> /// Called when a purchase completes successfully /// </summary> public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e) { string productID = e.purchasedProduct.definition.id; string purchaseToken = e.purchasedProduct.transactionID;
LootLockerSDKManager.RedeemGooglePlayStorePurchaseForPlayer(productID, purchaseToken, (result) => { if (!result.success) { Debug.Log("Redeem Purchase unsuccessful!"); return; } });
return PurchaseProcessingResult.Complete; }
/// <summary> /// Called when a purchase fails /// </summary> public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription) { Debug.Log($"Purchase failed: {failureDescription.reason}"); }
public void OnInitializeFailed(InitializationFailureReason error, string message) { Debug.Log("IAP Error: " + message); }}Coming soon
Redeem Purchase For Class
Product is from using UnityEngine.Purchasing;
It is possible to redeem a purchase for a class instead of a player, the flow is the same just that you use the function called RedeemGooglePlayStorePurchaseForClass instead.
public void RedeemPurchase(Product product){ string productID = product.definition.id; string purchaseToken = product.transactionID; int classID = 123; LootLockerSDKManager.RedeemGooglePlayStorePurchaseForClass(productID, purchaseToken, classID, (result) => { if (!result.success) { Debug.Log("Redeem Purchase unsuccessful!"); return; }
});}It is possible to redeem a purchase for a class instead of a player, the flow is the same just that you use the function called RedeemGooglePlayStorePurchaseForClass instead.
.dUzxoJGL_ZvHTt3.webp)
curl --location --request POST 'https://api.lootlocker.io/game/redeem/store/google' \--header 'x-session-token: {{session_token}}' \--header 'User-Agent: Apidog/1.0.0 (https://apidog.com)' \--header 'Content-Type: application/json' \--data-raw '{ "sandboxed": true, "transaction_id": "2000000316432499", "character_id": 123}'On a successful Purchase, a 204 will be returned with no body.
Conclusion
You now have the full Google Play Store purchase flow implemented: initiating a purchase using Google Play Billing, validating it through LootLocker, and granting rewards to the player.
With this setup, you can securely support Google Play in-app purchases while keeping your game logic centralized through LootLocker.
