Handling coins, virtual currency, points, beans(?!) etc in the In App Purchasing Plugin

I’ve had a few developers ask me how to handle stuff like virtual currency in my In-App Purchasing plugin. Out of the box it handles ‘Managed’ items like extra game levels, new swords, santa hats of health 😉 etc with ease. However ‘UnManaged’ items that can be purchased multiple times tend to be a little more specific to your game. You probably already have a virtual currency variable, like ‘coins’, somewhere in your code and you just want to increment this by say 100 when someone purchases a productid of ‘coins_100’.

Well luckily this is really simple to do. After a person purchases a productid in your game, the plugin will automatically call ‘OnPurchaseResponse’ on a script attached to the ‘UnityGameObjectReceiver’ gameobject. In the demo scene I use this fact to call ‘UpdatePurchase’ to record when a ‘Managed’ item has been purchased. This can be easily extended to handle your ‘UnManaged’ items in the following way:

public static void UpdatePurchase(PurchaseInfo purchaseInfo){
  if(purchaseInfo==null) return;
  Debug.Log("OrderID:" + purchaseInfo.orderId + " productId:" + purchaseInfo.productId + " purchaseState:" + purchaseInfo.purchaseState);
  if(purchaseInfo.purchaseState == "PURCHASED"){		//If a purchase then add to list of purchased items
    //Put any Unmanaged items here
    if(purchaseInfo.productId == "coins_100"){
      GlobalStuff.coins += 100;
    }
    //Managed Items
    if(!Instance.PurchaseInfos.Contains(purchaseInfo)){//Don't add again if this orderid already exists
      Instance.PurchaseInfos.Add(purchaseInfo);
      Save();//When you purchase an item, immediately save to file
    }
  }
}

Where ‘GlobalStuff.coins’ is your virtual currency variable, for example I tend to stick all my ‘globals’ in a ‘GameStateManager’ static class and expose them as static properties, so mine would actually be ‘GameStateManager.Coins’.

Note that you will probably want to save those precious coins for your players in between game sessions. PlayerPrefs is a good way to do this…

Hope that all makes sense. Of course this post covers the Android version of the plugin, however the iOS version is almost identical so can be amended in a similar way.

28 thoughts on “Handling coins, virtual currency, points, beans(?!) etc in the In App Purchasing Plugin

  1. Thank you for this post. Its the way i used but i wanted to be certain it was the right one.

    Another question : Have you a way to retrieve purchase if people change device ? I already passed through this problem by allowing people to cloud saving their data, but still, some people hates to create accounts…

    • Yes the ‘RestoreTransactions’ method retrieves all past managed purchases from google play. The demo code (using AndroidPurchases) actually looks for an existing ‘AndroidPurchases.PUR’ file on the device, if it doesn’t find it, presumes this is a new device and calls ‘RestoreTransactions’ to create and populate the ‘AndroidPurchases.PUR’ file with past transactions. Obviously this all presumes the user is using the same google account on the new device.

  2. Hey, got your IAP plugin, works great, no trouble at all, thanks a lot 😀 One thing though, is there a function called when RestoreTransactions() fails? ie when the user hits cancel on the sign in popup or something… Would be enormously helpful on the my Store page! Thanks a lot :)

    • Hi, glad you like the plugin! The script attached to the UnityGameObjectReceiver receives all the responses from the google, here are a couple of handy ones: The OnRestoreTransactionsResponse method gets called with a message “RESULT_OK” on a successful restore. The OnRequestPurchaseResponse gets called with message = “RESULT_USER_CANCELLED” if they cancel the purchase dialog. OnError should get called on any other errors. Safest is probably to presume the restore failed unless you get a “RESULT_OK”. Hope that helps and good luck with the games.

      • Ahh awesome, thats what I thought there would be 😛 Do I need to write this into the UnityGameObjectReciever? Or do I need to edit the code elsewhere? Thanks for your help man.

          • Ah, ok, I was talking Android! iOS is a bit less helpful with its callbacks. The ‘OnProvideContent’ method gets called on a restore for each ProductID. I use this fact to call UpdatePurchase and repopulate the local list of purchased products. Of course you can do the same and call any method of your own from this callback method. Note that if OnProvideContent doesn’t get called on a restore, the restore may have not failed, there may just not be anything to restore.

          • Ahh okay, so if I fire RestoreTransactions() then the only thing returned will be OnProvideContent, if there is a successful restore, nothing is fired if it is cancelled? (Fair enough if there is nothing to restore)….

  3. Thank you for your post.

    I bought your plugin in Unity3d assest store.

    And I used plugin my TestGame following your post.

    Awesome!!! I successfully purchased “Unmanaged Items” in my TestGame.

    But after purchase Items virtual currency variable(public static int medals;)
    is not changed.

    I used in my Scripts like this( public class Menu : MonoBehaviour )
    – void Purchase10() was used for another call.
    ===========================================================
    void Purchase10()
    {
    AndroidPurchases.PurchaseItem(“MyItem10”);
    }
    ===========================================================
    And I used in AndroidPurchases.cs Scripts following your post.
    ===========================================================
    if(purchaseInfo.productId == “MyItem10”)
    {
    medalmanager.medals += 5;
    Debug.Log (“Value 11111111111”);
    }
    ===========================================================
    But my virtual currency variable(public static int medals;) was not change.
    What’s the problem??
    My problem is, my virtual currency variable(public static int medals;) is not working when I purchased “Unmanaged Items”.

    Please help me~~~

    • Are you seeing the ‘Value 11111111111’ in the adb log? If not it probably means you are missing the ‘UnityGameObjectReceiver’ gameobject that is needed to receive the callbacks from the plugin (see demo and readme). If it is showing in the log then I see no reason why the variable shouldn’t be incrementing, is it getting reset somewhere? Writing the value out to the log (Debug.Log (“Medals: ″ + medalmanager.medals);) should help in tracking down the bug.

      • Please help me Please help me !!!!!!!!!!
        items you own:
        Fuel Log OnPurchaseError : {“mMessage” : “Unable to : 0
        Info : buy item ( response : 7 : Item Already Owned ) ” , ” mResponse ” : 7 }
        OnlabSetupFinished : { “mMessage” : ” Setup Successful . ( response : 0 : OK ) ” , ” mResponse ” : 0 }

        • This is usually due to your scene missing a UnityGameObjectReceiver gameobject hence the callback cannot be handled and the consume then doesn’t happen. See the ReadMe for details and take a look at the demo scene.

  4. hello
    i purchased in-app billing then i successfully testing managed item. It’s really great

    For unmanaged item should i put those sample code on my UnityGameObjectReceiver.cs?
    Or if you can, would you send me sample code for it?

    I’m pretty much new to these stuff.

    • Hi, thanks for your purchase. The code is an amendment to the UpdatePurchase method that resides in the AndroidPurchases class (AndroidPurchases.cs). Sorry if I didn’t make that clear. Like the post says, the code will be very specific to your needs so I can’t give you a more concrete example but it should be pretty straight forward. Good luck!

      • thank you for reply

        I have one more question

        I’m planning to purchase adroid bundle stuff

        if i buy it do i still need to merge mainfest?

  5. I’m really sorry, Can i have just one more question.
    I successful purchased unmanaged item with new code with demo build.
    But some how button never get back as enable state. what should i add to get button back to enable state so let tester continually buy unmaged stuff.

  6. Hi Plato,

    re your inapp purchase software.
    Working really well up to today!

    My google checkout account was recently changed over to the google wallet system.

    Google are progressively changing all customers,

    It appears that this may have broken the confirmation of product purchase back into my unity app.

    are you able to test this ASAP ?

    thanks Heaps
    Kingsley

  7. I’m also using your in-app android plug and Google wallet system.
    Purchasing managed and un-managed items works fine.
    Testing in a Goggle alpha state with real products and transaction. All work fine.

    Problem is with a managed item that has been refunded via Google wallet, ” Say I refund a in-app purchase of AdsOff” (after waiting 72hr.) AndroidPurchases.HasPurchased(“AdsOff”); still returns True when called.

    I assume its stuck pulling the data from the cache AndroidPurchases.PUR
    Is there a way to force reset of this cache file each time the game loads.
    or would calling AndroidPurchases.RestoreTransactions(); at the start of the game to refresh it?

    Using a near match to your demo script. Yet with the #if UNITY_EDITOR parts commented out.

    Thanks for any ideas.
    Bob

    • The demo code doesn’t handle refunds, however it should be pretty easy to add the ability to handle them. Basically you will need to handle the ‘OnPurchaseStateChange’ callback, look for a purchaseState of 2 and then maybe delete/amend the corresponding purchaseinfo.

      See this link for more details.

      The ‘cache file’ in the demo is completely under your control so if you want to reset it every time the game loads you could just never load the AndroidPurchases.PUR file (comment out instance = DeSerial.. etc will do it). Obviously this would mean the RestoreTransactions would have to pull the purchases down from the internet on every load…

  8. Hi, just purchased and wondering if you have these files in Java? I need it to work with my static vars as my game is in Java, I think moving files may cause mayhem!

    Thanks.

  9. Hello, I just purchased your product (IAP for android) and it is fantastically easy to use, and concise! But I encounter a problem: seems like AndroidJavaClass.RestoreTransactions does nothing.

    the UnityGameObjectReceiver does not react with OnRestoreTransactionsResponse and my purchases are not restored although I receive “ANDROID – RestoreTransactions” log (the step right before I am supposed to receive OnRestoreTransaction) .

    • When you do a restore, you should get a OnPurchaseResponse callback for each purchased managed item (if you are using the demo code this will repopulate the local list of purchased items which gets serialised out to AndroidPurchases.PUR). Check that you have UnityGameObjectReceiver with a script containing the OnPurchaseResponse method (like the demo) in the scene when you are doing a restore.

      • I couldn’t know what goes wrong with my implementation, but I try to restore a little later in the code (after the scene containing the GameObjectReceiver has been loaded) and everything works fine, true, in the first time I restore (in the initialization, loading Android Purchase, I did not have the GameObjectReceiver available so theres no way it could ever reach the GameObjectReceiver, but still it started normally with the .PUR, but when I cleared it, it never returned the purchases.

        As I said, retrying a little later in the code seems to have fixed it, but the normal flow of it makes it look like a bug. Thanks alot for the relatively quick response and a plugin that does exactly what it is supposed to do in a concise manner.

Leave a Reply

Your email address will not be published. Required fields are marked *