Coding Guidelines


After you've finished Google Play and Plugin Setup, you can proceed to scripting and implement InApps into your project. You may fill InApps setting pprogrammatically, in case  you do not want to use plugin editor settings by any reason. Following steps are not required if you already filled plugins settings as was described in the previous article. 

Note:  Following steps are not required, you may use plugin editor settings instead.

Setting Base64 key

AndroidNativeSettings.Instance.base64EncodedPublicKey = "YOUR_BASE64_KEY_HERE";

Registering the in-app products

You may add InApp products programmatically using the  

string MyProductSKU = "";

GoogleProductTemplate tpl = new GoogleProductTemplate();
tpl.SKU = MyProductSKU;

Connecting to billing service

Before connecting to the billing services I would recommend to subscribe to the billing events, to make sure you will not loose any event, since some event may be fired right after connection.  To connect to the billing service, all you need to do is to call Connect method of the billing client. See the code snippet bellow:

//listening for Purchase and consume events
AndroidInAppPurchaseManager.ActionProductPurchased += OnProductPurchased;  
AndroidInAppPurchaseManager.ActionProductConsumed  += OnProductConsumed;

//listening for store initialising finish
AndroidInAppPurchaseManager.ActionBillingSetupFinished += OnBillingConnected;

//you may use loadStore function without parameter if you have filled base64EncodedPublicKey in plugin settings

private static void OnBillingConnected(BillingResult result) {
	AndroidInAppPurchaseManager.ActionBillingSetupFinished -= OnBillingConnected;

	if(result.IsSuccess) {
	} else {
		Debug.Log("Connection failed");

Getting Inventory

After initialization is done (ActionBillingSetupFinished action fired) we can retrieve current user inventory.  With the following method:


Here is the example of parsing ActionBillingSetupFinished action and requesting product details.

private static void OnBillingConnected(BillingResult result) {
	AndroidInAppPurchaseManager.ActionBillingSetupFinished -= OnBillingConnected;

	if(result.IsSuccess) {
		//Store connection is Successful. Next we loading product and customer purchasing details
		AndroidInAppPurchaseManager.ActionRetrieveProducsFinished += OnRetrieveProductsFinised;

	AndroidMessage.Create("Connection Responce", result.Response.ToString() + " " + result.Message);
	Debug.Log ("Connection Responce: " + result.Response.ToString() + " " + result.Message);

After the ActionRetrieveProducsFinished will be fired we will get our inventory filled.

private static void OnRetrieveProductsFinised(BillingResult result) {
	AndroidInAppPurchaseManager.ActionRetrieveProducsFinished -= OnRetrieveProductsFinised;

	if(result.IsSuccess) {
		_isInited = true;
		AndroidMessage.Create("Success", "Billing init complete inventory contains: " + AndroidInAppPurchaseManager.Client.Inventory.Purchases.Count + " products");

		foreach(GoogleProductTemplate tpl in AndroidInAppPurchaseManager.Client.Inventory.Products) {
	} else {
		 AndroidMessage.Create("Connection Response", result.Response.ToString() + " " + result.Message);

	Debug.Log ("Connection Response: " + result.Response.ToString() + " " + result.Message);


Requesting inventory isn't required the step. But as for me it's very important, User android inventory contains information about user purchases, event if it was made on another devices, that's why when you doing In-Apps implementation for android you do not need "Restore Purchases" implementation, like for IOS. You will get all user purchases information with the android inventory.

As soon as  inventory ready, I would recommend going over products it contains and check if we need to unlock something.

Parsing Inventory

Let's say we have two products for our game. BONUS_TRACK - with is managed product for unlocking bonus tracks in your game. And CONIS_PACK - with is the unmanaged product for purchasing 100 in-game coins.

When inventory is loaded we can get states fo those products.  For example, our can be BONUS_TRACK purchased on another device, so we should unlock the track on the current device, or make sure that track is unlocked if  the BONUS_TRACK product purchased. Here is example ho we can do this:

if(AndroidInAppPurchaseManager.Client.Inventory.IsProductPurchased(BONUS_TRACK)) {
    if(!GameData.IsBonusTrackUnlocked) {


And we also need to check the CONIS_PACK product, in case it was purchased but wasn't consumed by or user. For example, app was closed when we were trying to consume the product. Wich means user has paid for the product but, he haven't got coins yet. So we will check if CONIS_PACK is purchased after inventory is loaded and will do the consume request it if necessary. Here is example:

if(AndroidInAppPurchaseManager.Client.Inventory.IsProductPurchased(CONIS_PACK)) {

See the AndroidInventory, GoogleProductTemplate, GooglePurchaseTemplate API Reference to find out more.

So, for example, If I need to know localized price string of the CONIS_PACK product, after inventory is loaded I can go like this:


Purchase And Consume

This is the easiest part. As you remember we already subscribe ActionProductPurchased and ActionProductConsumed in the init part, so now we can only run the purchase / consume flow for the products.

So here is how we will do purchase logic for our BONUS_TRACK(managed) and CONIS_PACK(unmanaged) products.  No matter what kind of product we need to purchase, for purchase flow start we should use following function:

AndroidInAppPurchaseManager.Client.Purchase (SKU);

After purchase flow is done, the ActionProductPurchased, and here is action parsing example:

private static void OnProductPurchased(BillingResult result) {
	if(result.IsSuccess) {
		AndroidMessage.Create ("Product Purchased", result.Purchase.SKU+ "\n Full Response: " + result.Purchase.OriginalJson);
		OnProcessingPurchasedProduct (result.Purchase);
	} else {
		AndroidMessage.Create("Product Purchase Failed", result.Response.ToString() + " " + result.Message);

	Debug.Log ("Purchased Responce: " + result.Response.ToString() + " " + result.Message);

The action contains BillingResult as parameter.

This flag will tell you if the purchase is available


information about purchase stored here


here is how for example you can get product SKU


See the BillingResult and GooglePurchaseTemplate to find out more.

So if the purchase was successful, we need to act depending on what product is purchased. If that is managed product like BONUS_TRACK, we can simply unlock the track and finish with our purchase flow.  But of that is the unmanaged product like CONIS_PACK  we need to consume the product and provide out player with coins only after consuming is successfully finished. Here is how our OnProcessingPurchasedProduct will look like.

private static void OnProcessingPurchasedProduct(GooglePurchaseTemplate purchase) {

    switch(purchase.SKU) {
    case COINS_ITEM:
    case BONUS_TRACK:

private static void OnProcessingConsumeProduct(GooglePurchaseTemplate purchase) {
	switch(purchase.SKU) {

If you implement subscription purchase in your application, you have to use 

AndroidInAppPurchaseManager.Client.Subscribe (SKU);

instead of 

AndroidInAppPurchaseManager.Instance.Purchase (SKU);

Result callbacks are the same as in general purchases.

If you want to implement the additional protecting level using Developer Payload,  you may specify it as the additional parameter for purchase.

string DeveloperPayload  = GeneratePayloadID();
AndroidInAppPurchaseManager.instance.purchase ("my_produtc_sku", DeveloperPayload);

And as was mentioned above you can find out purchase payload using GooglePurchaseTemplate  property.

Read more Security and Design.

Note: This step is not required.


You can find more API use examples under the plugin billing example scenes.

You also can use Playmaker Actions for game billing implementation.

And also watch these videos, with are covering pretty much the same what was described in this article: