Google Play InAppBilling, the complete guide
In this post, I am trying to include all the necessary steps to implement Google Play InAppBilling in Android. I will try to cover all the parts, from the Google Play Console to the code.
There is a good tutorial about the implementation of InAppBilling in the app side available here.
Before we start, you need to setup the following things:
- Google Play Developer Account requires $25 to open it for lifetime
- Google Merchant Account which you can also find at Settings and then like shown below
Now, if you have setup those things we are ready to roll.
For implementing the inapp purchase you need to upload the apk as alpha release with some of the code part. So first, let’s take a dive into the code section. The following steps are the same as in the InAppBilling implementation section.
- Download the InAppBillingService.aidl file from here.
- Create a directory named aidl under src/main.
- Add a new package com.android.vending.billing in this directory.
- Import the aidl file from step 1 to this package in step 3.
- Then in manifest file add this permission
<uses-permission android:name=”com.android.vending.BILLING” />
6. Now we need to create a ServiceConnection like this
ServiceConnection mServiceConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name,
IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
}
};
ServiceConnection is required to establish the connection with the InAppBilling service on Google Play.
7. Then you need to bind this service in the onCreate() method of your Activity like this
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent serviceIntent =
new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
}
8. Then on onDestroy() method you need to unbind this service like this
@Override
public void onDestroy() {
super.onDestroy();
if (mService != null) {
unbindService(mServiceConn);
}
}
If you don’t unbind, the open service connection could cause your device’s performance to degrade.
Now, we are ready to publish your app for the alpha release. To publish the app, you need to make a release apk by signing it with the release keystore. You can find the details about signing here.
Assuming that you have a release apk, now lets move onto the checklist required to publish your app as alpha release in the Play Store Console.
- 512*512 icon
- 1024*500 image
- At least 2 screenshots on mobile device
- If you are using dangerous permissions, any of the permission below, then you need to provide a privacy url also
READ_CALENDAR
WRITE_CALENDAR
CAMERA
READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
RECORD_AUDIO
READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
BODY_SENSORS
SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
If you have all these requirements above, then we are ready to publish the apk.
If you haven’t already bought the Google Play Developer account then buy it, if you have then go to this url. I will list the steps involved in adding the app as alpha release in steps below.
Remember, once we complete all the steps below and release the app as alpha, we cannot delete our application, we can unpublish it but we cannot delete it and if we need to publish the same app again we need to change it’s package name.
- Create Application by clicking on the blue Create Application at right side of the console.
- Select the default language and then give the name of your application as the Title and we are now redirected to the Store Listing section
- In store listing section add the title, short description, full description then upload the 2 screenshots or more in the phone section and upload the hi-res icon and feature graphic icon, select the application type and category of your application and then give a url to the privacy policy part if you are using dangerous permission and click on save draft at the right top of the console. For content rating we need to upload to the apk first, so let’s do that.
- Go to App Releases section and click on manage alpha, create release, upload the apk there, the apk must be signed apk, upload the apk there and there should be a green tick and if you press back button you should see a screen as shown at the bottom of these steps.
- Now we to mange the testers, for testing method, I will choose Open Alpha Testing Method, and below will the opt-in url and we can share it to those who we want to become a tester for our app. I will add a screenshot below
- Now to Content Rating, there will be certain sets of questionnaire about the app, appropriately tick them and apply that content rating.
- Then to Pricing and Distribution, select and tick all those that are necessary for your app and save draft, there it will show what are the missing requirements for your app, if it shows any, fulfill them and publish your application. It might take certain hours for your app to get published.
Screenshots for steps 4 and 5
Now, finally we will be diving into the real inapp purchase part.
First we have to add a product that our customers/users can buy, for that Goto Store Presence>InAppProducts>Add New Products.
There are two types of Product we can add on Google Play.
- Managed Product :
Managed in-app products are items that have their ownership information tracked and managed by Google Play. When a user purchases a managed in-app item, Google Play stores the purchase information for each item on a per-user basis. This enables you to later query Google Play at any time to restore the state of the items a specific user has purchased. This information is persistent on the Google Play servers even if the user uninstalls the application or if they change devices.
If you are using the In-app Billing API, you can also consume managed items within your application. You would typically implement consumption for items that can be purchased multiple times (such as in-game currency, fuel, or magic spells). Once purchased, a managed item cannot be purchased again until you consume the item, by sending a consumption request to Google Play.
In a nutshell, managed products are those products which are purchased for one time purpose only and if we are to purchase the same item again, we need to consume it.
2. Subscription :
A subscription is a product type offered in In-app Billing that lets you sell content, services, or features to users from inside your app with recurring monthly or annual billing. You can sell subscriptions to almost any type of digital content, from any type of app or game.
With the In-app Billing API, you can use the same purchase flow for buying subscriptions and retrieving subscription purchase information as with in-app products.
Unlike in-app products, subscriptions cannot be consumed.
In a nutshell, subscription products are those products which are purchased for certain time, 7 days, 1 month etc and it will be expired and we need to buy it again, and we don’t need to consume it.
Remember : We cannot delete the Subscription product once we create it but we can delete and modify a Managed product.
So, now let’s select Managed Product and the Product ID is the SKU, which needs to be unique and we will need to specify this ProductID/SKU in the code. Add the title, description and the price for this product and activate it from the top right side corner.
Now we are ready to implement the billing part in the app side.
I am assuming that you have a button or a view and on its onClick() you will be calling the InAppPurchase. We have already added the ServiceConnection class and also bound the InAppVendingBillingService at the beginning of this post.
Now, on onClick() of the view, first we need to check if the device supports the billing or not, like this
public boolean isBillingSupported() {
int response = 1;
try {
response = mService.isBillingSupported(3, getPackageName(), "inapp");
} catch (RemoteException e) {
e.printStackTrace();
}
if (response > 0) {
return false;
}
return true;
}
The parameter 3, is the version of InAppBilling, and last one “inapp” is the string type for managed products, for subscription type we should use “subs”.
Now, I have a method which prompts the Google Play in app billing dialog.
private void purchaseItem(String sku) {
try {
if (isBillingSupported()) {
Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
sku, "inapp", "developer_payload");
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
try {
startIntentSenderForResult(pendingIntent.getIntentSender(),
1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0),
Integer.valueOf(0));
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
alert("Billing is not supported");
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
The parameter, sku is the ProductID we have created in the Google Play Console, tv_show_55, in the screenshot above.
The
developer_payload
String is used to specify any additional arguments that you want Google Play to send back along with the purchase information. Don’t use thedeveloper_payload
field for security validation purposes. This field isn't always available when completing tasks related to In-app Billing.If you run the app, at this time, you will see the Google Play Billing dialog. There might be some error like, authentication or product not found for that the gmail account in the device you are testing needs to be a Tester by clicking Become a Tester in the opt in url.
For testing purpose, we can use this as SKU android.test.purchased and if we run the app we will see a dialog like this
Now if we click the same item, the app will crash, to solve this hit this code in the terminal, the crash is because we need to consume a managed product
adb shell pm clear com.android.vending
startIntentSenderForResult will call the onActivityForResult() method of our Activity.
onActivityForResult will be like this
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1001) {
int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
if (resultCode == RESULT_OK) {
try {
JSONObject jo = new JSONObject(purchaseData);
String sku = jo.getString("productId");
String purchaseToken = jo.getString("purchaseToken");
alert("You have bought the " + sku + ". Congratulations!");
consumeItem(purchaseToken);
} catch (Exception e) {
alert("Failed to parse purchase data.");
e.printStackTrace();
}
}
}
}
The value of jo JsonObject will be like this
{"packageName":"com.packagename","orderId":"transactionId.android.test.purchased",
"productId":"android.test.purchased","developerPayload":"developer_payload",
"purchaseTime":0,"purchaseState":0,"purchaseToken":"inapp:com.packagename:android.test.purchased"}
This way, we purchase an item from the Google Play.
Now, if the product is Managed Product, we need to consume it, otherwise the app will crash. I have a method to consume a product like this
private void consumeItem(String purchaseToken) {
int response = 0;
try {
response = mService.consumePurchase(3, getPackageName(), purchaseToken);
} catch (RemoteException e) {
e.printStackTrace();
}
Observable<Integer> consumeObs = Observable.just(response);
consumeObs.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).unsubscribeOn(Schedulers.io())
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer value) {
Timber.d("value of string in consume %s",value);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
});
}
The code part below is a network call so we need to run it asynchronously
response = mService.consumePurchase(3, getPackageName(), purchaseToken);
I have used RxJava for this purpose, if you find it difficult you can use AsyncTask also, by adding the above code snippet in the doInBackground() and returning the integer in the onPostExecute().
I am consuming the managed product as soon the customer/user buys it.
So, this is it, this is the complete tutorial on how to implement the Google Play InApp billing. If I had made some mistakes or misunderstood something, please comment. If you have any queries you can find me on twitter.