Reminder: Starting on August 2, 2021, all new apps must use Billing Library version 3 or newer. By November 1, 2021, all updates to existing apps must use Billing Library version 3 or newer. Learn more.
Joining the question!
Need release
Joining
Please upgrade
Joining
Please~~
please upgrade.
Same warning. Pls upgrade library
Joining please.
Please upgrade!
@serggl wake up bro
Please update v3 soon..
following
Me too following
+1
It will be great 👯♀️
Joining the question!
Need release
Pls upgrade library
Joining the question!
please update
+1
+1
I have made an Android Library to manage Google Play Billing, In App Purchases and Subscriptions with just a few lines of code.
Check it out and be sure to star the project if you liked my contribution :)
+1
+1
Please update +1
+1
IMO, this library isn't needed anymore. Google Play billing v2 offered a very low-level AIDL, but v3 offers a Kotlin/Java API. The AIDL API required a lot of boilerplate code for handling raw data and making requests. The Kotlin/Java API offered by v3 takes care of that, which is also one of the pain points that this library addressed for v2. Unlike v2, v3 also queries Play Store's cache on querying purchases. A major chunk of this library was dedicated to maintaining this cache.
The v3 library doesn't address verifying purchases. You can copy-paste the Security class for that. Your licenseKey is the public key for verifying purchases. productId, purchaseData and dataSignature are returned by Purchase#getSku(), Purchase#getOriginalJson() and Purchase#getSignature() respectively.
On a side note, you are now required to either acknowledge or consume all purchases. You also need to handle pending purchases that may transition to the purchased state while the user is away from your app.
After trying to make this project compatible with v3, I gave up and using only the v3 itself, It is not complicate to use, you can follow this sample https://medium.com/@programtown/how-to-make-in-app-purchase-in-android-using-google-play-billing-library-updated-library-3-0-1-72e0b1fd43d5 or more advance sample of Google ClassyTaxiJava https://github.com/android/play-billing-samples/blob/main/ClassyTaxiJava/app/src/main/java/com/sample/android/classytaxijava/billing/BillingClientLifecycle.java , change the BillingClient.SkuType.SUBS to BillingClient.SkuType.INAPP for use with non subscription
Please upgrade
thanks to @dzungpv i was able to update my library to 3.0.1, still testing, will comment after testing.
Billing Library v-3
Demo Application :- https://github.com/Mahadev-code/AndroidInAppPurchase
Source code also tested on Google Play store
Bump, Please update
Any idea what to do? It seems that there won't be any update.
class BillingProvider constructor(
val context: Context,
val license:String,
val productsList:List
var purchaseStatusUpdate: ((purchases: List
) : PurchasesUpdatedListener {
init {
initBillingClient()
}
//var purchaseStatusUpdate: ((productId:String,status:Boolean)->Unit)? = null
private var billingClient: BillingClient? = null
private fun initBillingClient() {
billingClient = BillingClient.newBuilder(context)
.enablePendingPurchases().setListener(this).build()
billingClient?.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
val queryPurchase = billingClient?.queryPurchases(BillingClient.SkuType.INAPP)
val queryPurchases =
queryPurchase?.purchasesList
if (queryPurchases != null && queryPurchases.size > 0) {
handlePurchases(queryPurchases,true)
} else {
purchaseStatusUpdate(null,false)
}
}
else
purchaseStatusUpdate(null,false)
}
override fun onBillingServiceDisconnected() {
purchaseStatusUpdate(null,false)
}
})
}
open fun handlePurchases(purchases: List<Purchase>,isRestore:Boolean= false) {
val billingItems = ArrayList<BillingItem>()
for (purchase in purchases) {
//if item is purchased
if (productsList.contains(purchase.sku) && purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
if (!verifyValidSignature(purchase.originalJson, purchase.signature)) {
// Invalid purchase
// show error to user
billingItems.add(BillingItem(purchase.sku, false))
context.showMessege("Error : Invalid Purchase")
return
}
// else purchase is valid
//if item is purchased and not acknowledged
if (!purchase.isAcknowledged) {
billingItems.add(BillingItem(purchase.sku, true))
val acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient?.acknowledgePurchase(acknowledgePurchaseParams) {
// val result = (it.responseCode == BillingClient.BillingResponseCode.OK)
// purchaseStatusUpdate(listOf(BillingItem(purchase.sku, result)))
}
} else {
}
billingItems.add(BillingItem(purchase.sku, true))
} else if (productsList.contains(purchase.sku) && purchase.purchaseState == Purchase.PurchaseState.PENDING) {
context.showMessege("Purchase is Pending. Please complete Transaction")
billingItems.add(BillingItem(purchase.sku, false))
} else if (productsList.contains(purchase.sku) && purchase.purchaseState == Purchase.PurchaseState.UNSPECIFIED_STATE) {
billingItems.add(BillingItem(purchase.sku, false))
}
}
purchaseStatusUpdate(billingItems,isRestore)
}
private fun verifyValidSignature(
signedData: String,
signature: String
): Boolean {
return try {
// To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
Security.verifyPurchase(license, signedData, signature)
} catch (e: IOException) {
false
}
}
override fun onPurchasesUpdated(
billingResult: BillingResult,
purchases: MutableList<Purchase>?
) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
handlePurchases(purchases)
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
val queryAlreadyPurchasesResult: Purchase.PurchasesResult? =
billingClient?.queryPurchases(
BillingClient.SkuType.INAPP
)
val alreadyPurchases: List<Purchase>? = queryAlreadyPurchasesResult?.getPurchasesList()
alreadyPurchases?.let { handlePurchases(it) }
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
context.showMessege("Purchase Canceled")
} else {
context.showMessege(
"Error " + billingResult.getDebugMessage()
)
}
}
private fun initiatePurchase(activity: Activity, itemId: String) {
val skuList = ArrayList<String>()
skuList.add(itemId)
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
billingClient?.querySkuDetailsAsync(
params.build()
) { billingResult, skuDetailsList ->
if (billingResult.responseCode === BillingClient.BillingResponseCode.OK) {
if (skuDetailsList != null && skuDetailsList.size > 0) {
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsList[0])
.build()
billingClient?.launchBillingFlow(activity, flowParams)
} else {
//try to add item/product id "purchase" inside managed product in google play console
context.showMessege(
"Purchase Item not Found"
)
}
} else {
context.showMessege(
" Error " + billingResult.debugMessage
)
}
}
}
fun requsetPaymment(activity: Activity, itemId: String) {
if (billingClient?.isReady==true) {
initiatePurchase(activity,itemId)
} else {
billingClient =
BillingClient.newBuilder(context).enablePendingPurchases().setListener(this).build()
billingClient?.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode === BillingClient.BillingResponseCode.OK) {
initiatePurchase(activity,itemId)
} else {
context.showMessege(
"Error " + billingResult.debugMessage)
}
}
override fun onBillingServiceDisconnected() {
}
})
}
}
}
data class BillingItem(val productId: String, val status: Boolean)
kindly use the above helper class like this:
private fun startBillingProcess() {
billinProvider = BillingProvider(this,BillingData.APP_LICENSE,BillingData.listProducts){itemsList,isRestore->
itemsList?.forEach {
if(it.productId==BillingData.REMOVE_ADS_ID && it.status)
preferenceManager.removeAds = true
}
}
}
Most helpful comment
IMO, this library isn't needed anymore. Google Play billing v2 offered a very low-level AIDL, but v3 offers a Kotlin/Java API. The AIDL API required a lot of boilerplate code for handling raw data and making requests. The Kotlin/Java API offered by v3 takes care of that, which is also one of the pain points that this library addressed for v2. Unlike v2, v3 also queries Play Store's cache on querying purchases. A major chunk of this library was dedicated to maintaining this cache.
The v3 library doesn't address verifying purchases. You can copy-paste the Security class for that. Your
licenseKeyis the public key for verifying purchases.productId,purchaseDataanddataSignatureare returned by Purchase#getSku(), Purchase#getOriginalJson() and Purchase#getSignature() respectively.https://github.com/anjlab/android-inapp-billing-v3/blob/23b702219e7449e99ba94ace21cbe2cdb6eb6e8d/library/src/main/java/com/anjlab/android/iab/v3/BillingProcessor.java#L173-L177
https://github.com/anjlab/android-inapp-billing-v3/blob/23b702219e7449e99ba94ace21cbe2cdb6eb6e8d/library/src/main/java/com/anjlab/android/iab/v3/BillingProcessor.java#L1009-L1024
On a side note, you are now required to either acknowledge or consume all purchases. You also need to handle pending purchases that may transition to the purchased state while the user is away from your app.