If you missed part 1 of this series, read about the basics and how to secure iOS in-app purchases here. In this post, I will build on the existing PCL from the iOS sample. Make sure to take a look at the full source code here if you need the full picture.
Implementing secure in-app purchases for Google Play is a bit trickier than iOS for several reasons. The Android APIs are a bit more involved, and Android's openness lends itself to more hacking, in general.
For example, here are the kinds of things Android users can do (a bit more easily than iOS):
NOTE: I would not recommmend installing any of these things without doing your own research
So for getting started with this, I followed Google's Java sample and ported it to C# (using C# idioms). The very first thing you need will be an Android aidl file, along with a custom one needed for Xamarin apps. You can think of AIDL as Android's version of a contract for interprocess communication. Read more on the topic here.
To set them up in your project, download IInAppBillingService.aidl and Bundle.aidl from my sample here, and set the build action to AndroidInterfaceDescription in Visual Studio/Xamarin Studio. Doing this will generate several C# classes for interacting with the Android billing service from within your application.
If you are using proguard, which I highly recommend for apps using Java libraries (Google Play Services, etc.). You will need to add the following to your Proguard.cfg file:
Using proguard is a good idea in general, as it obfuscates and strips unused code from any Java libraries your application is using. Since we have an aidl file that doesn't map to a Java class included in our app, it will get stripped by proguard without adding an exemption.
Before we start anything, go ahead and add permissions for android.permission.INTERNET and com.android.vending.BILLING to your Android application, as they are needed for in-app billing to work.
Next, let's define several constants that we will need to use throughout our GooglePlayPurchaseService. These were ported from the Java sample, and we may not need to use them all.
With that out of the way, we need to implement an IServiceConnection for billing. Its job is to connect to the Android billing service and instantiate a IInAppBillingService instance our app can use for interprocess communication.
We really only need two methods here: Connect and Disconnect, and also need a way to retrieve the interface to the billing service. We are using TaskCompletionSource to wrap the callback in a Task for async/await.
To actually get to the point of making IAPs, let's implement how prices are retrieved. We will be calling IInAppBillingService.GetSkuDetails, which returns JSON that we will need to parse ourselves. I used JSON.NET and a strongly-typed private class to do this work:
To move forward from here, I would recommend doing the setup on the Google Play console side at this point. Go ahead and setup the following for your app:
One other thing to keep in mind for debugging IAPs, is that all of the following have to match a build uploaded to Google Play: android:versionCode, android:versionName, your package name, and the keystore.
There is a trick here, that I think should help alot of people with this. There is a special debug keystore file used for debug builds of Xamarin apps with an alias of androiddebugkey and a password of android. It is generated when you install Xamarin, but it generally located in either:
What you can do to debug IAPs in an emulator, real device, etc. is to modify your official Google Play keystore file so that the alias and passwords match the debug key. Then you simply have to copy over top of the Xamarin-generated key, and the next time you debug it will be signed with your Google Play keystore.
It is a bit tricky to modify your key in this manner via command line, so I setup a quick shell script to do it:
I have a windows version here as well. From here all you need to do is copy over Xamarin's key (back it up, of course), and you will be able to debug with your official Android keystore.
For completing a purchase, there are quit a bit of hoops to jump through. In general:
So our BuyNative implementation looks like:
That is only half of the implementation, and I'm leaving out my handling of ResultItemAlreadyOwned. Next, we need a HandleActivityResult method for Android to notify us the result of the purchase. I recommend using an IoC/DI container of some kind to manage your purchase service so your Activity can call it.
From here, make sure to pass the results of OnActivityResult from your activity to this service. You will also need to fill out the PublicKey property with the key found in the Google Play dev console. NOTE: it is also a good idea to obsfuscate the key in your app in some way. I recommend using James Montemagno's method here
Just like on iOS, alot of things have to be in order on the Google Play developer console before you can actually complete a real purchase.
You probably should go ahead and verify everything is working at this point and make a real purchase, before adding server-side validation. One thing to keep in mind, is that there is actually an option for giving users free purchases from your Google Play account. If you go to Settings | Developer Account | Account Details | License Testing, you can add as many users are you like that will not be charged for IAPs.
Now that we've gone through all that work, we can actually validate the purchase on a server to prevent any tomfoolery. I recommend using something like Azure Functions if your app does not have a backend.
For our function, we will need the NuGet package for Google.Apis.AndroidPublisher.v2, which gives you the ability to validate Google Play receipts from C#. Without further ado, here is the Azure function I came up with:
See the full source code for the Azure function here.
GooglePlayAccount and GooglePlayKey will need to be filled out as application settings for your Azure function. Generating these keys is somewhat of a pain to setup, it is the same process that you would use for authentication when pushing automated builds to Google Play.
This process can be summed up by:
Finally, we have make one small change to our PurchaseService base class. In our Buy method, we need to add:
I'm sorry it took so long to get the Google Play version of this post completed, but you can see how it was somewhat painful to set up. However, I think it is very important to add extra levels of protection for IAPs on Android. Implementing server-side checking, should prevent users from getting free IAPs in your app from software like Freedom, etc. If you get stuck with anything in this post, feel free to leave a comment below and I'll help you out.