Knowledge base

Purchasing integration (iOS)

Overview

Unity allows you to use its optimized monetization features without implementing Unity IAP. Use Unity Ads 3.0+ to create IAP Promos and leverage Personalized Placements while maintaining your own in-app purchasing solutions, by following these basic steps:

  1. Install Unity Ads SDK 3.0+ for your Project.
  2. Manually configure your Product Catalog on the Developer Dashboard.
  3. Configure an IAP Promo on the dashboard
  4. Implement a purchasing adapter in your game code, using the USRVUnityPurchasing API.
  5. Implement game logic and purchase events within the purchasing adapter.
  6. Initialize the purchasing adapter and Monetization SDK.

Implementation

The following instructions are for iOS developers using Objective-C.

  • If you are a Unity developer using custom IAP solutions, click here.
  • If you are an Android developer using Java, click here.

Importing the Unity Ads framework

Download the Unity Ads framework here. The USRVUnityPurchasing API requires SDK 3.0 or later.

  1. Drag-and-drop the framework into your Unity Project folder, and copy it.
  2. In your ViewController header (.h), import Unity Ads and set the Unity Ads delegate:
#import <UIKit/UIKit.h>
#import <UnityAds/UnityMonetization.h>

@interface ViewController: UIViewController<UnityMonetizationDelegate, UMONShowAdDelegate>
@end

Creating a Project in the Unity Developer Dashboard

If you don't have a Unity Developer (UDN) account yet, create one here. When you have an account, follow these steps to create a Unity Project:

  1. Log in to the Developer Dashboard, and navigate to the Operate tab.
  2. Select Projects from the left navigation bar.
  3. Click the NEW PROJECT button in the top right corner.

Locate your Project’s Game ID by selecting your Project, then selecting Monetization > Platforms from the left navigation bar. Copy the Apple App Store Game ID, because you need it to activate the Unity Ads service in your game.

Configuring your Product Catalog on the Developer Dashboard

Before implementing your Monetization purchasing delegate, navigate to the Operate tab of the Developer Dashboard, then follow the manual configuration instructions for populating a Product Catalog.

Configuring your Promotion on the Developer Dashboard

From the Operate tab of the Developer Dashboard, follow the instructions for configuring an IAP Promo.

Modifying your code

Implementing the purchasing delegate

In your game script, include the <UnityAds/USRVUnityPurchasingDelegate.h> delegate, then implement the USRVUnityPurchasing class that manages the USRVUnityPurchasingDelegate delegate. You will use two functions, loadProducts and purchaseProduct, to define the game logic you want the purchasing adapter to use. These methods require a class using USRVUnityPurchasing. You must implement them so the SDK can call them as needed when managing your Product transactions.

#import <UnityAds/USRVUnityPurchasingDelegate.h>

@interface MyPurchasing <USRVUnityPurchasingDelegate>
@end

// Placeholder for loadProducts function

// Placeholder for purchaseProduct function
Retrieving your Product Catalog

The SDK calls loadProducts to retrieve the list of available Products, using the UnityPurchasingLoadProductsCompletionHandler function to convert UPURProduct objects into Monetization.Product objects. This requires at minimum a productID, localizedPriceString, productType, isoCurrencyCode, and localizedTitle string for each Product.

Processing a purchase

The SDK calls purchaseProduct when a user clicks the buy button for a promotional asset. The purchase’s success or failure handling depends on your in-app purchasing implementation.

If the transaction succeeds, call the UnityPurchasingTransactionCompletionHandler function using a UPURTransactionDetails object.

If the transaction fails, call the UnityPurchasingTransactionErrorHandler function, using a UPURTransactionError object.

Finally, set the delegate using [USRVUnityPurchasing setDelegate: [[MyPurchasing alloc] init]].

Example USRVUnityPurchasingDelegate implementation
#import <UnityAds/USRVUnityPurchasingDelegate.h>

@interface MyPurchasing <USRVUnityPurchasingDelegate>
@end

@implementation MyPurchasing
-(void) loadProducts: (UnityPurchasingLoadProductsCompletionHandler) completionHandler {

    completionHandler (@[[UPURProduct build: ^(UPURProductBuilder *builder) {
        builder.productId = @"100BronzeCoins";
        builder.localizedTitle = @"100 Bronze Coins";
        builder.localizedPriceString = @"$1.99";
        builder.localizedPrice = [NSDecimalNumber decimalNumberWithString: @"1.99"];
        builder.isoCurrencyCode = @"USD";
        builder.localizedDescription = @"Awesome Bronze Coins available for a low price!";
        builder.productType = @"Consumable";
    }]]);
}

-(void) purchaseProduct: (NSString *) productId completionHandler: (UnityPurchasingTransactionCompletionHandler) completionHandler errorHandler: (UnityPurchasingTransactionErrorHandler) errorHandler userInfo: (nullable NSDictionary *) extras {
    thirdPartyPurchasing.purchase (productId); // Generic developer purchasing function

    // If purchase succeeds:
    completionHandler ([UPURTransactionDetails build: ^(UPURTransactionDetailsBuilder *builder) {
        builder.productId = productId;
        builder.transactionId = thirdPartyPurchasing.transactionId;
        builder.currency = @"USD";
        builder.price = [NSDecimalNumber decimalNumberWithString: @"1.99"];
        builder.receipt = @"{\n\"data\": \"{\\\"Store\\\":\\\"fake\\\",\\\"TransactionID\\\":\\\"ce7bb1ca-bd34-4ffb-bdee-83d2784336d8\\\",\\\"Payload\\\":\\\"{ \\\\\\\"this\\\\\\\": \\\\\\\"is a fake receipt\\\\\\\" }\\\"}\"\n}";
    }]);

    // If purchase fails:
    errorHandler (kUPURTransactionErrorNetworkError, nil);
}
@end

Initializing the purchasing delegate and SDK

After you’ve implemented the purchasing adapter, you must provide a reference to it using the setDelegate method. Finally, you must initialize the SDK using your Project’s Game ID for the appropriate platform. You can locate the ID on the Operate tab of the Developer Dashboard by selecting a Project, then selecting Monetization > Platforms from the left navigation bar.

To avoid errors, implement these calls as early as possible in your game’s run-time life cycle. For example:

#import "ViewController.h"

@implementation ViewController

- (void) viewDidLoad {
    [super viewDidLoad];
    [USRVUnityPurchasing setDelegate: [[MyPurchasing alloc] init]];
    [UnityMonetization initialize: @"1234567" delegate: self testMode: true];
}
@end

Back to top

iOS API

USVRUnityPurchasing

A static class that manages the purchasing delegates, which are delegates for the SDK to retrieve the information it needs from your custom IAP implementation.

@interface USRVUnityPurchasing: NSObject
+(void) setDelegate: (id<USRVUnityPurchasingDelegate>) delegate;
+(nullable id<USRVUnityPurchasingDelegate>) getDelegate;
@end

USVRUnityPurchasingDelegate

A delegate that the developer implements, and passes back to the SDK.

typedef void (^UnityPurchasingLoadProductsCompletionHandler) (NSArray<UPURProduct*>*);
typedef void (^UnityPurchasingTransactionCompletionHandler) (UPURTransactionDetails*);
typedef void (^UnityPurchasingTransactionErrorHandler) (UPURTransactionError, NSException*);

@protocol USRVUnityPurchasingDelegate
-(void) loadProducts: (UnityPurchasingLoadProductsCompletionHandler) completionHandler;
-(void) purchaseProduct: (NSString *) productId 

    completionHandler: (UnityPurchasingTransactionCompletionHandler) completionHandler

        errorHandler: (UnityPurchasingTransactionErrorHandler) errorHandler
            userInfo: (nullable NSDictionary *) extras;
@end

loadProducts

The SDK calls this to retrieve the list of available Products. It uses the UnityPurchasingProductsCompletionHandler function, which takes a UPURProduct object to register your products. For example:

-(void) loadProducts: (UnityPurchasingLoadProductsCompletionHandler) completionHandler {

    completionHandler (@[[UPURProduct build:^(UPURProductBuilder *builder){
        builder.productId = @"100BronzeCoins";
        builder.localizedTitle = @"100 Bronze Coins";
        builder.localizedPriceString = @"$1.99";
        builder.localizedPrice = [NSDecimalNumber decimalNumberWithString:@"1.99"];
        builder.isoCurrencyCode = @"USD";
        builder.localizedDescription = @"Awesome Bronze Coins available for a low price!";
        builder.productType = @"Consumable";
    }]]);
}
UPURProduct

An IAP product converted into an object that the SDK can use for optimizing monetization.

Set the following fields on the @interface UPURProductBuilder: NSObject builder, then call +(instancetype) build: (void (^) (UPURProductBuilder *)) buildBlock to construct the final object:

Property Description
@property (strong, nonatomic, readonly) NSString *productId An internal reference ID for the Product.
@property (strong, nonatomic, readonly) NSString *localizedTitle A consumer-facing name for the Product, for store UI purposes.
@property (nonatomic, readonly) NSDecimalNumber *localizedPrice A consumer-facing price string, including the currency sign, for store UI purposes.
@property (strong, nonatomic, readonly) NSString *localizedPriceString The internal system value for the Product’s price.
@property (strong, nonatomic, readonly) NSString *isoCurrencyCode The ISO code for the Product’s localized currency.
@property (strong, nonatomic, readonly) NSString *localizedDescription A consumer-facing Product description, for store UI purposes.
@property (strong, nonatomic, readonly) NSString *productType Unity supports "Consumable", “Non-consumable”, and “Subscription” Product Types.

For more details on Product properties, see documentation on Defining Products.

purchaseProduct

The SDK calls this when a user clicks the buy button for a promotional asset. Unity passes the purchased Product’s ID to your in-app purchasing system. The function uses the UnityPurchasingTransactionCompletionHandler and UnityPurchasingTransactionErrorHandler functions to handle the purchase’s success or failure according to your implementation.

UnityPurchasingTransactionCompletionHandler

Your custom game logic for handling a successful transaction. In the below example, a successful transaction calls UnityPurchasingTransactionCompletionHandler, which builds a UPURTransactionDetails object.

UnityPurchasingTransactionErrorHandler

Your custom game logic for handling a failed transaction. The function takes a TransactionDetails object. In the example below, a failed transaction calls UnityPurchasingTransactionErrorHandler, which returns a UPURTransactionError enum.

Example purchaseProduct implementation
-(void) purchaseProduct: (NSString *) productId completionHandler: (UnityPurchasingTransactionCompletionHandler) completionHandler errorHandler: (UnityPurchasingTransactionErrorHandler) errorHandler userInfo: (nullable NSDictionary *) extras {
    thirdPartyPurchasing.purchase (productId); // Generic developer purchasing function

    // If purchase succeeds:
    completionHandler ([UPURTransactionDetails build: ^(UPURTransactionDetailsBuilder *builder) {
        builder.productId = productId;
        builder.transactionId = thirdPartyPurchasing.transactionId;
        builder.currency = @"USD";
        builder.price = [NSDecimalNumber decimalNumberWithString: @"1.99"];
        builder.receipt = @"{\n\"data\": \"{\\\"Store\\\":\\\"fake\\\",\\\"TransactionID\\\":\\\"ce7bb1ca-bd34-4ffb-bdee-83d2784336d8\\\",\\\"Payload\\\":\\\"{ \\\\\\\"this\\\\\\\": \\\\\\\"is a fake receipt\\\\\\\" }\\\"}\"\n}";
    }]);


    // If purchase fails:
    errorHandler (kUPURTransactionErrorNetworkError, nil);
}
@end
UPURTransactionDetails

An IAP transaction receipt converted into an object that the SDK can use for optimizing monetization.

Property Description
@property (strong, nonatomic, readonly) NSString *productId An internal reference ID for the Product.
@property (strong, nonatomic, readonly) NSString *transactionId An internal reference ID for the transaction.
@property (strong, nonatomic, readonly) NSString *receipt The JSON fields from the appStoreReceiptURL detailing the transaction. Encode the receipt as a JSON object containing Store, TransactionID, and Payload.
@property (strong, nonatomic, readonly) NSDecimalNumber *price The internal system value for the Product’s price.
@property (strong, nonatomic, readonly) NSString *currency The ISO code for the Product’s localized currency.

For more details, see Apple’s documentation on In-App Purchase Receipt Fields.

UPURStore

An enum indicating which store the transaction is from.

typedef NS_ENUM (NSInteger, UPURStore) {
    kUPURStoreNotSpecified,
    kUPURStoreGooglePlay,
    kUPURStoreAmazonAppStore,
    kUPURStoreCloudMoolah,
    kUPURStoreSamsungApps,
    kUPURStoreXiaomiMiPay,
    kUPURStoreMacAppStore,
    kUPURStoreAppleAppStore,
    kUPURStoreWinRT,
    kUPURStoreTizenStore,
    kUPURStoreFacebookStore
};
NSString *NSStringFromUPURAppStore(UPURStore);
UnityPurchasingTransactionError

An enum indicating the reason a transaction failed.

typedef NS_ENUM (NSInteger, UPURTransactionError) {
    kUPURTransactionErrorNotSupported,
    kUPURTransactionErrorItemUnavailable,
    kUPURTransactionErrorUserCancelled,
    kUPURTransactionErrorNetworkError,
    kUPURTransactionErrorServerError,
    kUPURTransactionErrorUnknownError
};
NSString *NSStringFromUPURTransactionError (UPURTransactionError);

UnityAnalytics

The SDK provides Unity Analytics APIs to non-Unity developers, to help optimize monetization. Implement the following analytic events and pass them back to the SDK, to help analyze your game’s economy. The more information the SDK has about your players’ behavior, the better it manages your monetization strategy.

@interface UnityAnalytics: NSObject

onItemAcquired

Call this event when players purchase an item in-game.

+ (void) onItemAcquired: (NSString *) transactionId itemId: (NSString *) itemId transactionContext: (NSString *) transactionContext level: (NSString *) level itemType: (NSString *) itemType amount: (float) amount balance: (float) balance acquisitionType: (UnityAnalyticsAcquisitionType) acquisitionType;

onItemSpent

Call this event when players consume or spend an item in-game.

+ (void) onItemSpent: (NSString *) transactionId itemId: (NSString *) itemId transactionContext: (NSString *) transactionContext level: (NSString *) level itemType: (NSString *) itemType amount: (float) amount balance: (float) balance acquisitionType: (UnityAnalyticsAcquisitionType) acquisitionType;
Parameter Type Description
transactionContext NSString A description of the in-game context for the transaction (for example, "Loot box").
amount NSFloat The quantity of the resource acquired.
itemId NSString An internal reference ID for the acquired resource.
balance NSFloat The player’s new (post-transaction) quantity of the acquired resource.
itemType NSString The category of the resource required (for example, “Premium currency”).
level NSString The name or ID of the level/area where the player acquired the resource (for example, “Level 1 store”).
transactionId NSString An internal reference ID for the transaction. You can optionally use this identifier to group multiple events into a single transaction.
acquisitionType UnityAnalyticsAcquisitionType Indicates soft or premium currency.

These events help train the SDK to know when it’s best to show a Promo. Consider the following examples:

If a player has purchased 300 Gold Coins and spent 250, the data model can determine that they are getting low on Gold Coins, and that it might be worthwhile to show a Promo for acquiring more.

[UnityAnalytics onItemAcquired: @"ABCD" itemId: @"300goldCoins" transactionContext: @"3rd level store" level: @"3" itemType: @"in-game-currency" amount: 300.0F balance: 300.0F acquisitionType: kUnityAnalyticsAcquisitionTypePremium];

[UnityAnalytics onItemSpent: @"ABCD" itemId: @"250goldCoins" transactionContext: @"4th level store" level: @"4" itemType: @"in-game-item" amount: 250.0F balance: 50.0F acquisitionType: kUnityAnalyticsAcquisitionTypePremium];

If a player trades 100 Cows for 400 Pigs, the data model can determine that it might be worthwhile to show a Promo for replenishing the Cows they depleted.

[UnityAnalytics onItemAcquired: @"ABCD" itemId: @"400pigs" transactionContext: @"Newbie Bazaar" level: @"newbieBazaar" itemType: @"in-game-currency" amount: 400.0F balance: 400.0F acquisitionType: kUnityAnalyticsAcquisitionTypeSoft];

[UnityAnalytics onItemSpent: @"ABCD" itemId: @"100cows" transactionContext: @"Newbie Bazaar" level: @"newbieBazaar" itemType: @"in-game-item" amount: 100.0F balance: 0.0F acquisitionType: kUnityAnalyticsAcquisitionTypeSoft];
UnityAnalyticsAcquisitionType

An enum that indicates whether an item is kUnityAnalyticsAcquisitionTypeSoft (in-game currency) or kUnityAnalyticsAcquisitionTypePremium (exchanged for real world money).

typedef NS_ENUM (NSInteger, UnityAnalyticsAcquisitionType) {
    kUnityAnalyticsAcquisitionTypeUnset,
    kUnityAnalyticsAcquisitionTypeSoft,
    kUnityAnalyticsAcquisitionTypePremium
};
NSString *NSStringFromUnityAnalyticsAcquisitionType (UnityAnalyticsAcquisitionType);

onLevelFail

Call this when players fail a level in-game. The data model can use this to show a Promo for a Product that will help them pass the level on the next playthrough.

+ (void) onLevelFail: (int) levelIndex;

onLevelUp

Call this when players complete a level. When used in conjunction with onLevelFail, the data model gains insight into which levels users are struggling with, and which Promos make effective offers for each level.

+ (void) onLevelUp: (int) theNewLevelIndex;

Back to top

Still need help? Get in touch!
Last updated on 16th Nov 2018