Google Play Billing Library on Android: That time I had to add payments to the app
--
How many times, during the development of an app, have you found yourself faced with the thousands of articles, links and questions on stackoverflow, regarding Billing?
How many times have you had to deploy the app to find out if everything was correct or if everything worked correctly?
How many times have you said “enough, I will not pay, the guides are all crap!”?
Me many times, but I hope not to be included in one of those mentioned above :-).
The biggest problem is not implementing the payment method, but understanding what to do step by step to make sure everything works correctly.
What I will try to do in this article will be to enclose in a single document the steps to follow in order to add a payment method within your app, using Android Studio as the IDE and Kotlin as the programming language.
Another key point is the following:
I will focus in particular on consumables and how to “consume” them. Well then, we agree. Let’s begin.
Step 1: Create A Google Play Developer Account
In order to implement payments in the app, we will first need to create a Google Play developer account.
Note: by the time of speaking Google Play charges a $25 one-time developer fee.
- Go to https://play.google.com/apps/publish/signup/
- Click Create an Account.
3. Fill out the form then click Next Step.
4. Click Back to Google Play Developer Console.
5. Select the Google Play Developer distribution agreement check-box to acknowledge your agreement, and click Continue to payment to pay the one-time $25 fee.
6. Enter your payment information, and click Accept and continue.
7. You will receive an email from Google notifying you when your account is ready to be activated.
Note: This process can take up top a week.
8. Activate your account.
Congratulations, you can now submit your app to the Google Play store. Enjoy!!! :-)
Step 2: User Permission
We create the app we want to publish from Android Studio. It doesn’t matter what our app looks like, we’ll think about that later.
The most important thing now is to activate in-app purchases on the Android Studio side and publish the app from the Google Play Console, before proceeding.
Then open your Manifest and add the following line:
<uses-permission android:name="com.android.vending.BILLING" />
Step 3: Create and publish an App in the Google Play Developer Console
Go back to the Google Play Console to be able to publish it in the store. On this point, creating an app is really very intuitive.
But before starting two small notes:
- Make sure you have signed up as a Google Play developer. For more information, read the article “Android — Set-up Your Google Play Developer Account.”
- If you have not previously created a keystore file, now would be a good time to create one. For more information, click here.
Step 4: Add your personal in-app products
Once the app has been published with the billing permissions inside the bundle/apk we will see the “products” section active where it will be possible to set the price of the app (if we want our app to be paid), the in-app products and subscriptions.
In this guide I will focus on the second, the in-app product.
To enable in-app product for your app, do the following:
- Open the Google Play Console.
- Select your app.
- Go to Products > In-app product.
Once you have clicked on “in-app products” it’s time to add all the consumables that we will use within our application.
Click on create product, enter your product ID, product details and price and then click on save at the bottom right.
Once created you should see something like this:
Note: Once the product has been saved, you will no longer be able to change its ID. This is important for two reasons: the first is that the product ID is the element that on the code side (Android Studio side) we will go to fetch to continue with the payment steps, so my advice is to think first about which ID associated with each product.
Step 5: Integrate the Google Play Billing Library into your app
If we have done everything correctly now we just need to implement everything in the app, so now some code :-).
Let’s add the dependencies we need in the gradle:
5.1 Initialize a BillingClient & Establish a connection to Google Play
Once you’ve added a dependency on the Google Play Billing Library, you need to initialize a BillingClient
instance. Use newBuilder()
to create a BillingClient.
private lateinit var billingClient: BillingClientbillingClient = BillingClient.newBuilder(Dodgers.context!!)
.enablePendingPurchases()
.setListener(this@MyBilling)
.build()
5.2 Implement PurchasesUpdatedListener to receive updates on purchases
override fun onPurchasesUpdated(
billingResult: BillingResult,
purchases: MutableList<Purchase>?
) {//TODO: not implemented}
5.3 Establish a connection to google play using startConnection()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
// The BillingClient is setup successfully
loadAllSKUs()
} else {
skuDetailsList = mutableListOf()
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
Log.e(TAG, "error")
}
})
Now we need to call theloadAllSKUs()
function. If BillingClient has been configured correctly we need to download the list of items we have previously added from in-app products from our Google Play Console (STEP 4).
Define new SKUlist
private val skuList: List<String> = listOf(
"first_product_id"
)
Then pass your newly created list to the .setSkusList () method to confirm that your list is contained in the one implemented in the Google Play Console
private var skuDetailsList: MutableList<SkuDetails> = mutableListOf()
private fun loadAllSKUs() = if (billingClient.isReady) {
val params = SkuDetailsParams
.newBuilder()
.setSkusList(skuList)
.setType(BillingClient.SkuType.INAPP)
.build()
billingClient.querySkuDetailsAsync(params) { billingResult, skuDetailsList ->
// Process the result.
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && skuDetailsList!!.isNotEmpty()) {
this.skuDetailsList = skuDetailsList
} else this.skuDetailsList = mutableListOf()
}
} else {
println("Billing Client not ready")
}
5.4 Launch the purchase flow
if (skuDetailsList.isNotEmpty()) {
val skuDetails = skuDetailsList.first { it.sku == myItem .sku }
val billingFlowParams = BillingFlowParams
.newBuilder()
.setSkuDetails(skuDetails)
.build()
billingClient.launchBillingFlow(requireActivity(), billingFlowParams)
} else {
showSnackBar("Error | sku list is empty")
}
5.5 Handle possible response codes
Once the action is initiated, we need to manage the response through onPurchasesUpdated() method like below:
override fun onPurchasesUpdated(
billingResult: BillingResult,
purchases: MutableList<Purchase>?
) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
for (purchase in purchases) {
acknowledgePurchase(purchase, purchase.sku)
}
} else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
Log.e(TAG, "User Canceled action")
} else {
// Handle any other error codes.
Log.e(TAG, "An error occurred handling code")
}
}
To acknowledge non-consumable purchases, use either BillingClient.acknowledgePurchase()
from the Billing library. This can be useful when the selected item is unique and cannot be bought again
private fun acknowledgePurchase(purchase: Purchase, sku: String) {
val params = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient.acknowledgePurchase(params) { billingResult ->
val responseCode = billingResult.responseCode
val debugMessage = billingResult.debugMessage
CoroutineScope(Dispatchers.Main + exceptionHandler).launch {
val skuItem = Gem.values().find { it.sku == sku }
// Do something with skuItemSelected and purchased
}
//if(shouldConsumeItem)
//consumeItemPurchased(purchase)
}
}
Done. the item selected on click and the purchase action was successful, you do not need anything else but to manage the action after the purchase in your app as you see fit. If, on the other hand, you want the item to be available again for a new purchase then you will have to consume the same as soon as the user has purchased it and this means calling the method consumeItemPurchased():
private fun consumeItemPurchased(purchase: Purchase) {
// Verify the purchase.
// Ensure entitlement was not already granted for this purchaseToken.
// Grant entitlement to the user.
val consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient.consumeAsync(consumeParams) { billingResult, outToken ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
// Handle the success of the consume operation.
LogHelper.log(TAG, "Item Consumed!!!")
}
}
}
Summarizing everything in a single class we will have:
By following these simple, but not at all quick, steps you will have the opportunity to create your own payment client from scratch, without having to jump from link to link to find all the pieces and without having to follow articles that refer to what the console of Google Play, considering that for more than a month they have done a restyle and therefore many items are impossible to find.
Obviously I wanted to concentrate this article on Consumables and non-Consumables but I think it is the minimum necessary to implement payments in your application or in your games. For all that I have not been able to enclose, you will surely find the link that shows you all the useful details on the payment client useful. Making a comparison with the things you are missing from my guide.