Coding Guidelines

Connection

First of all,  you need to connect InApp client to the billing services. Best practice is to do this on your app start.

UM_InAppPurchaseManager.Client.Connect();

As soon, connection flow finished will be initialized you will get connection finish event. OnServiceConnected event is fired. See the implementation example bellow:

//subscribing to init finish action
UM_InAppPurchaseManager.Client.OnServiceConnected += OnBillingConnectFinishedAction;
UM_InAppPurchaseManager.Client.Connect();

private void OnBillingConnectFinishedAction (UM_BillingConnectionResult result) {
	UM_InAppPurchaseManager.Client.OnServiceConnected -= OnBillingConnectFinishedAction;
	if(result.isSuccess) {
		Debug.Log("Connected");
	} else {
		Debug.Log("Failed to connect");
	}
}  

You can also find out current connection state with the IsConnected property:

UM_InAppPurchaseManager.Client.IsConnected

If connection is failed (for example, no internet connection available) you can try to call connect  later. But you shouldn't use any of billing API before UM_InAppPurchaseManager is successfully initialized. 

Also, you should keep in mind that initialization on Android is always successful, read more in the Platform behavior differences chapter.

After successful initialization, you can retrieve data about current available products. You can get info using InAppProducts property:

UM_InAppPurchaseManager.InAppProducts;

You can also get product template using following methods:

static UM_InAppProduct GetProductById(string id);
static UM_InAppProduct GetProductByIOSId(string id);
static UM_InAppProduct GetProductByAndroidId(string id);
static UM_InAppProduct GetProductByAmazonId(string id);
static UM_InAppProduct GetProductByWp8Id(string id);
	

More information about loaded product template can be retrieved with UM_InAppProduct class. 

The code snippet bellow show's how to retrieve general available products info:

foreach(UM_InAppProduct product in UM_InAppPurchaseManager.InAppProducts) {
	Debug.Log("Id: " + product.id);
	Debug.Log("IsConsumable: " + product.IsConsumable);

	Debug.Log("Title: " + product.Title);
	Debug.Log("Description: " + product.Description);
	Debug.Log("Price: " + product.Price);

	Debug.Log("IOSId: " + product.IOSId);
	Debug.Log("AndroidId: " + product.AndroidId);
	Debug.Log("WP8Id: " + product.WP8Id);
}

Making a Purchase

To purchase product use:

UM_InAppPurchaseManager.instance.Purchase(YOUR_PRODUCT_ID);

As soon as purchase flow is finished, you will get purchase finish event. To subscribe for an event you can use OnPurchaseFinished action. See the code snippet bellow.

Example:

UM_InAppPurchaseManager.Client.OnPurchaseFinished += OnPurchaseFlowFinishedAction;
UM_InAppPurchaseManager.Client.Purchase(YOUR_PRODUCT_ID);

private void OnPurchaseFlowFinishedAction (UM_PurchaseResult result) {
	UM_InAppPurchaseManager.Client.OnPurchaseFinished -= OnPurchaseFlowFinishedAction;
	if(result.isSuccess) {
		UM_ExampleStatusBar.text = "Product " + result.product.id + " purchase Success";
	} else  {
		UM_ExampleStatusBar.text = "Product " + result.product.id + " purchase Failed";
	}
}

You may always check if a product was already purchased with IsProductPurchased method.:

UM_InAppPurchaseManager.Client.IsProductPurchased(YOUR_PRODUCT_ID);

There is also a specific feature for the IOS Platform. If you have non-consumable items in your game you should also implement restore purchases  button, since it required by Apple. When restore flow is started you will get OnPurchaseFinished event fired for each non-consumable product purchased by a user.

UM_InAppPurchaseManager.instance.RestorePurchases();

Note: You should send restore purchases request is user clicked "Restore Purchases" button in your game store.

Note: Restore purchases not required on Android and WP8, because all user purchases info is available after connecting to billing service.

So for example, you have the non-consumable item  "Coins Booster" in your game and you want to add an ability to purchase it in your project. On IOS And Android platform. Here is what you need to do:

  1. Add the product to your IOS app in iTunes, with id: ios.booster.id
  2. Add the product to the developer console, with id: android.booster.id

Then create this booster product in the UM plugin settings. Open:

Windows ->  Stan's Assets -> Ultimate Mobile -> Edit Settings

And add the booster product as showed on the screenshot bellow:

As you see we created the product with id booster.  We also specified IOS SKU for this product from iTunes and Android SKU from Google Play Console.

Note: Do not forget to set Base64Key for android, if you going to use purchases on android platform.

And now if we want to purchase this product on any platform we will simply use this cross-platform code for your booster product:

UM_InAppPurchaseManager.Client.Purchase("booster");

Platform behavior differences  

The initialization on Android is always successful. Since Android billing API using local cache. However attempt to purchase product will be failed due to connection issue. Also you  should keep in mind that you will not get up to date user purchases info you will get local purchase cache stored by google on device since last application launch.

On Android platform we do not have consumable or non-consumable, starting from Android billing API v3 all products are managed (consumable)  which means the developer is deciding by he self, consumer product or not after product is purchased based on product id. 

Once product is purchased it will be stored in the Android inventory. The same product can be purchased while we have it in our inventory. So for example, if we need consumable product logic, right after product is purchased, we will remove it from inventory using consume method, and product will be available for purchasing again. And of course we should add  (coins, energy, etc) only be consume successes event.

And the same if we would like to implement the non-consumable product logic, we will not use consume method, and will unlock non-consumable content (tracks, cars, levels, customization, etc) by purchase successes event. And since we will never remove it from the inventory after products being purchased, user will not able to purchase it twice.

With Ultimate Mobile plugin part of this logic is handled by the plugin, but you should understand ho it works anyway. So if using Ultimate Mobile plugin settings you set product as consumable UM_InAppPurchaseManager.OnPurchaseFlowFinishedAction action will be fired after product is purchased and consumed.  From the non-consumable product UM_InAppPurchaseManager.OnPurchaseFlowFinishedAction  action will be fired after products is purchased.

After billing is connected (UM_InAppPurchaseManager.OnBillingConnectFinishedAction event was fired) you can find out is non-consumable product state (if it's purchased or not), see the code snippet bellow:

string productId = "product_id_as_specified_in_plugin_settings";
bool IsPurchased = UM_InAppPurchaseManager.Client.IsProductPurchased("productId");

IsProductPurchased method can be used for non-consumable products only, since consumable products will be removed from the inventory (consumed) right after begin purchased, So for the consumable products this methods will always return false.

More example can be found in the UM_BillingExample.cs script.

Scripting Reference

UM_InAppPurchaseManager

public class UM_InAppPurchaseManager {
	static UM_InAppClient Client {get;}
	static List<UM_InAppProduct> InAppProducts {get;}

	static UM_InAppProduct GetProductById(string id);
	
	static UM_InAppProduct GetProductByIOSId(string id);
	
	static UM_InAppProduct GetProductByAndroidId(string id);

	static UM_InAppProduct GetProductByAmazonId(string id);
	
	static UM_InAppProduct GetProductByWp8Id(string id);
}

UM_InAppClient

public interface UM_InAppClient {
	//Actions
	event Action<UM_BillingConnectionResult>  OnServiceConnected;
	event Action<UM_PurchaseResult> OnPurchaseFinished;
	event Action<UM_BaseResult> OnRestoreFinished;


	/// <summary>
	/// Connect to Android InApp service
	/// ActionBillingSetupFinished Action fired when connect
	/// is complete
	/// </summary>
	void Connect();


	/// <summary>
	/// Start purchase flow for product
	/// ActionProductPurchased Action fired when flow
	/// is complete
	/// </summary>
	/// <param name="SKU">product SKU you want to purchase</param>
	void Purchase(string productId);


	/// <summary>
	/// Start purchase flow for product
	/// ActionProductPurchased Action fired when flow
	/// is complete
	/// </summary>
	/// <param name="SKU">product SKU you want to purchase</param>
	void Purchase(UM_InAppProduct product);

	/// <summary>
	/// Start subscribe flow for product
	/// ActionProductPurchased Action fired when flow
	/// is complete
	/// </summary>
	/// <param name="SKU">product SKU you want to purchase</param>
	void Subscribe(UM_InAppProduct product);


	/// <summary>
	/// Start purchase flow for product
	/// ActionProductPurchased Action fired when flow
	/// is complete
	/// </summary>
	/// <param name="SKU">product SKU you want to purchase</param>
	void Subscribe(string productId);


	/// <summary>
	/// Restores purchases made by current user
	/// OnPurchaseFinished Action will be  fired for eatch previously purchaed product
	/// When restore flow is complete, OnRestoreFinished action fired.
	/// </summary>
	void RestorePurchases();


	/// <summary>
	/// Returns true if product with provided id owned by user
	/// <param name="productId">product Id</param>
	/// </summary>
	bool IsProductPurchased(string productId);


	/// <summary>
	/// Returns true if provided product  owned by user
	/// <param name="productId">product object</param>
	/// </summary>
	bool IsProductPurchased(UM_InAppProduct product);


	/// <summary>
	/// Can be used to determine if app is connection
	/// to the Android billing services 
	/// </summary>
	bool IsConnected {get;}
}

UM_InAppProduct

public class UM_InAppProduct {

	string LocalizedPrice  { get; }
	string CurrencyCode { get; }
	long PriceAmountMicros { get; }
	string ActualPrice { get; }
	float ActualPriceValue { get; }
	bool IsPurchased { get; }
	

	WP8ProductTemplate WP8Template { get; }
	IOSProductTemplate IOSTemplate { get; }
	GoogleProductTemplate AndroidTemplate { get; }
	AmazonProductTemplate AmazonTemplate { get; }
	UM_InAppProductTemplate template { get; }
}