With the Qonversion API, I am adding a feature for users to purchase subscriptions. When the user comes back after the purchased subscription, I want to check the subscription status, but I get a "null" value from checkEntitlements as a return. At the same time, although the purchase is positive in the purchase function, it does not enter onSuccess at all. How can I check the user's subscription status? (When I try to subscribe again after the purchase is made, google says I am already subscribed, so the subscription process is successful.)
Fragment:
class PurchaseFragment : Fragment() {
private var _binding: FragmentPurchaseBinding? = null
private val binding get() = _binding!!
private var product: QProduct? = null
Displaying product:
private fun displayProducts() {
Qonversion.shared.offerings(object : QonversionOfferingsCallback {
override fun onSuccess(offerings: QOfferings) {
val mainOffering = offerings.main
if (mainOffering != null && mainOffering.products.isNotEmpty()) {
binding.monthlyPrice.text = mainOffering.products[0].prettyPrice
product = mainOffering.products[0]
}
}
override fun onError(error: QonversionError) {
Log.d(TAG, "Error: $error")
}
})
}
Making purchase:
private fun makePurchase(product: QProduct) {
Qonversion.shared.purchase(
requireActivity(),
product,
callback = object : QonversionEntitlementsCallback {
override fun onSuccess(entitlements: Map<String, QEntitlement>) {
val premiumEntitlement = entitlements["premium_permisson"]
if (premiumEntitlement != null && premiumEntitlement.isActive) {
Log.d(TAG, "Entitlements: $premiumEntitlement")
} else {
Log.d(TAG, "Entitlements else: $premiumEntitlement")
}
}
override fun onError(error: QonversionError) {
// Handle error here
if (error.code === QonversionErrorCode.CanceledPurchase) {
Log.d(TAG, "Canceled")
}
}
})
}
Check status of user:
private fun isItPremiumUser() {
Qonversion.shared.checkEntitlements(object : QonversionEntitlementsCallback {
override fun onSuccess(entitlements: Map<String, QEntitlement>) {
val premiumEntitlement = entitlements["premium_permisson"]
Log.d(TAG, "isItPremiumUser $premiumEntitlement") // it returns null
if (premiumEntitlement != null && premiumEntitlement.isActive) {
Log.d(TAG, "isItPremiumUser Entitlements: $premiumEntitlement")
// handle active entitlement here
// also you can check renew state if needed
// for example to check if user has canceled subscription and offer him a discount
when (premiumEntitlement.renewState) {
QEntitlementRenewState.NonRenewable -> {
Log.d(TAG, "NonRenewable Entitlements: $premiumEntitlement")
// NonRenewable is the state of a consumable or non-consumable in-app purchase
}
QEntitlementRenewState.WillRenew -> {
Log.d(TAG, "WillRenew Entitlements: $premiumEntitlement")
// WillRenew is the state of an auto-renewable subscription
}
QEntitlementRenewState.BillingIssue -> {
Log.d(TAG, "BillingIssue Entitlements: $premiumEntitlement")
// Prompt the user to update the payment method.
}
QEntitlementRenewState.Canceled -> {
Log.d(TAG, "Canceled Entitlements: $premiumEntitlement")
// The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
// Prompt the user to resubscribe with a special offer.
}
else -> {
Log.d(TAG, "else Entitlements: $premiumEntitlement")
}
}
}
}
override fun onError(error: QonversionError) {
// handle error here
Log.d(TAG, "onError: $error")
}
})
}
Related
I have two subscriptions in the application, each of them individually works correctly. But when I try to do an Update/Downgrade, problems arise:
I have two subscriptions in the application, each of them individually works correctly. But when I try to do an Update/Downgrade, problems arise:
When I try to change one subscription to another, I get the correct window with changing the subscription and shows that the new subscription was purchased successfully, but when I check on Google Play, it shows only the one I bought first, after a while I try again, this time it does not appear replacement window, only the standard purchase window, the second one is bought without problems and both are visible in the Store. Maybe I have some wrong approach to updating, everything seems to be in its place otherwise, the window with the replacement would not be displayed correctly.
My setSuccessfulScreen() method, in onPurchasesUpdated(), works correctly on the first purchase, but it crashes with an error when I try to update the subscription:
Fatal Exception: java.lang.RuntimeException: Error receiving broadcast Intent { act=com.android.vending.billing.PURCHASES_UPDATED
I thought maybe the case in Binding, I replaced with findViewById(), it does not help, without this method there is no crash.
My subscription code:
private fun buySubscription() {
val skuList = ArrayList<String>()
skuList.add("")
skuList.add("")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS)
billingClient!!.querySkuDetailsAsync(params.build()) { billingResult, skuDetailsList ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
when (subsFlag) {
MONTH -> {
if (!ProviderPreferences.isSubscribed()) {
billingClient!!.launchBillingFlow(requireActivity(), BillingFlowParams.newBuilder().setSkuDetails(skuDetailsList[1]!!).build())
} else {
if (ProviderPreferences.getSubscribedType() == MONTH) {
billingClient!!.launchBillingFlow(requireActivity(), BillingFlowParams.newBuilder().setSkuDetails(skuDetailsList[1]!!).build())
} else {
val updateParams = BillingFlowParams.SubscriptionUpdateParams.newBuilder().setOldSkuPurchaseToken(ProviderPreferences.getPurchaseToken()!!).setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.DEFERRED).build()
billingClient!!.launchBillingFlow(requireActivity(), BillingFlowParams.newBuilder().setSkuDetails(skuDetailsList[1]!!).setSubscriptionUpdateParams(updateParams).build())
}
}
}
YEAR -> {
if (!ProviderPreferences.isSubscribed()) {
billingClient!!.launchBillingFlow(requireActivity(), BillingFlowParams.newBuilder().setSkuDetails(skuDetailsList[0]!!).build())
} else {
if (ProviderPreferences.getSubscribedType() == YEAR) {
billingClient!!.launchBillingFlow(requireActivity(), BillingFlowParams.newBuilder().setSkuDetails(skuDetailsList[0]!!).build())
} else {
val updateParams = BillingFlowParams.SubscriptionUpdateParams.newBuilder().setOldSkuPurchaseToken(ProviderPreferences.getPurchaseToken()!!).setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.DEFERRED).build()
billingClient!!.launchBillingFlow(requireActivity(), BillingFlowParams.newBuilder().setSkuDetails(skuDetailsList[0]!!).setSubscriptionUpdateParams(updateParams).build())
}
}
}
}
}
}
}
private fun purchases() {
val acknowledgePurchaseResponseListener = AcknowledgePurchaseResponseListener { billingResult -> }
billingClient = BillingClient.newBuilder(App.getInstance()).enablePendingPurchases().setListener { billingResult: BillingResult, list: List<Purchase>? ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
val purchase = list!![0]
handlePurchases(acknowledgePurchaseResponseListener, purchase)
ProviderPreferences.saveSubscriptionType(subsFlag)
ProviderPreferences.savePurchaseToken(list[0].purchaseToken)
setSuccessfulScreen()
}
}.build()
connectToGooglePlayBilling()
}
private fun handlePurchases(acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener?, purchase: Purchase) {
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
ProviderPreferences.saveSubscription(true)
if (!purchase.isAcknowledged) {
val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.purchaseToken).build()
billingClient!!.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener!!)
}
}
}
private fun connectToGooglePlayBilling() {
billingClient!!.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
billingClient!!.queryPurchasesAsync(BillingClient.SkuType.SUBS) { billingResult, list ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && list != null) {
}
}
}
override fun onBillingServiceDisconnected() {
connectToGooglePlayBilling()
}
})
}
private fun setSuccessfulScreen() {
group!!.visibility = View.GONE
group2!!.visibility = View.VISIBLE
subscribeBtn!!.visibility = View.GONE
lottieAnimation!!.playAnimation()
}
I am using the billing v4 library.
Please tell me what could be the reason, maybe something is wrong with the subscription change code, I have not worked with subscription renewal before. And what could be the reason for the crash.
Thank you in advance.
I have integrated the google play billing library inside my application to make a subscription purchase. It works well. The user receives purchase confirmation mail from google.
confirmation mail from google
The active subscription is also visible in the play store subscriptions screen.
Active subscription showing in play store
In the play console, the order detail said the user was successfully charged for a subscription. However, It gets canceled instantly.
play console order history
I also check purchase acknowledgment, it returns true on every purchase. Initially, I thought there would be a mistake in my code. So, I tried various billing libraries from Github. The problem persists. In the end, I replaced the entire google billing library with Revenue cat. Followed every step described on Revenue cat documents. Still, getting the same issue.
Is there anything that I am missing to implement or done incorrectly? please help me out. Thank you
code for fetching available products:
private fun fetchOffering(){
Purchases.sharedInstance.getOfferingsWith({ error ->
// An error occurred
handleBillingError(requireActivity(), error)
}) { offerings ->
offerings.current?.availablePackages?.takeUnless { it.isNullOrEmpty() }?.let {
// All packages from current offering
if (it.isNotEmpty()){
it.forEach { p: Package ->
offeringPackages.add(p)
}
isProductsAvailable = true
}
Log.d("RevenueCat", "fetchOffering: success: ${it.size}")
}
}
}
code for making purchase:
private fun makePurchase(pack:Package){
Purchases.sharedInstance.purchasePackageWith(
requireActivity(),
packageToPurchase = pack /* package from the fetched Offering*/,
onError = {error, userCancelled ->
Log.d("RevenueCat", "makePurchase: userCancelled: $userCancelled")
handleBillingError(requireActivity(), error)
},
onSuccess = { product, purchaserInfo ->
if (purchaserInfo.entitlements[REVENUE_ENTITLEMENT_ID_PRO]?.isActive == true) {
Log.d("RevenueCat", "makePurchase: success: ${product.originalJson} ")
afterPurchaseSuccessSetup()
}
})
}
I don't know where you are lagging, you should follow these steps to make subscribe purchase.
private lateinit var billingClient: BillingClient
private val skuListsubscribe = listOf("subscription_1", "subscription_2")
initialize billing client.
private fun setupBillingClient() {
billingClient = BillingClient.newBuilder(BaseActivity.mContext!!)
.enablePendingPurchases()
.setListener(this)
.build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
loadAllSKUsSubscription()
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
Log.e("TAG", "onBillingServiceDisconnected: ")
}
})
}
private fun loadAllSKUsSubscription() = if (billingClient.isReady) {
val params = SkuDetailsParams
.newBuilder()
.setSkusList(skuListsubscribe)
.setType(BillingClient.SkuType.SUBS)
.build()
billingClient.querySkuDetailsAsync(params) { billingResult, skuDetailsList ->
// Process the result.
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && skuDetailsList!!.isNotEmpty()) {
for (skuDetails in skuDetailsList) {
if (skuDetails.sku == subscribtionId) {
tv_full_category_price.text = skuDetails.price
realAmountSubscription = skuDetails.price
rl_bestvalue_plan.setOnClickListener {
isInAppPurchase = false
isSubscribtion = true
val billingFlowParams = BillingFlowParams
.newBuilder()
.setSkuDetails(skuDetails)
.build()
billingClient.launchBillingFlow(requireActivity(), billingFlowParams)
}
}
}
}
}
} else {
println("Billing Client not ready")
}
override purchase update method
override fun onPurchasesUpdated(
billingResult: BillingResult,
purchases: MutableList<Purchase>?,
) {
if (billingResult?.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
for (purchase in purchases) {
acknowledgePurchase(purchase)
}
} else if (billingResult?.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
//logger("User Cancelled")
//logger(billingResult?.debugMessage.toString())
} else {
//logger(billingResult?.debugMessage.toString())
}
}
private fun acknowledgePurchase(purchase: Purchase) {
if (isSubscribtion) {
handleNonConsumableProduct(purchase = purchase)
}
}
fun handleConsumableProduct(purchase: Purchase) {
val consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient.consumeAsync(consumeParams) { billingResult, purchaseToken ->
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
if (isVisible && isAdded)
Snackbar.MakeInternetSnackbar(BaseActivity.mContext!!,
subscription_fragment_indicator_layout,
"Purchased Successfully")
InAppPaymentApi(realAmount.toString(), audio_id!!, purchase.purchaseToken)
}
}
}
Facing an issue with IMMEDIATE app update mode. After successful completion of app update, everything is closed and not restarting the app. That is the issue.
But android documentation says:
A full screen user experience that requires the user to update and
restart the app in order to continue using the app. This UX is best
for cases where an update is critical for continued use of the app.
After a user accepts an immediate update, Google Play handles the
update installation and app restart.
implementation 'com.google.android.play:core:1.9.1'
implementation 'com.google.android.play:core-ktx:1.8.1'
code
class MainActivity : AppCompatActivity() {
companion object {
const val UPDATE_REQUEST_CODE = 112
const val TAG = "MainActivity"
}
private var appUpdateManager: AppUpdateManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<TextView>(R.id.tv_text).text = "Version " + BuildConfig.VERSION_NAME
// Returns an intent object that you use to check for an update.
appUpdateManager = AppUpdateManagerFactory.create(this)
}
private val listener: InstallStateUpdatedListener =
InstallStateUpdatedListener { installState ->
if (installState.installStatus() == InstallStatus.DOWNLOADED) {
// After the update is downloaded, show a notification
// and request user confirmation to restart the app.
Log.d(TAG, "An update has been downloaded")
} else if (installState.installStatus() == InstallStatus.INSTALLED) {
Log.d(TAG, "An update has been installed")
}
}
override fun onStart() {
super.onStart()
checkAppVersionNew()
}
private fun checkAppVersionNew() {
val appUpdateInfoTask = appUpdateManager!!.appUpdateInfo
appUpdateInfoTask.addOnSuccessListener { result: AppUpdateInfo ->
if (result.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && result.isUpdateTypeAllowed(
AppUpdateType.IMMEDIATE
)
) {
try {
Log.d(TAG, "An update available")
appUpdateManager!!.startUpdateFlowForResult(
result,
AppUpdateType.IMMEDIATE,
this,
UPDATE_REQUEST_CODE
)
} catch (e: SendIntentException) {
Log.d(TAG, "SendIntentException $e")
e.printStackTrace()
}
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == UPDATE_REQUEST_CODE) {
when (resultCode) {
RESULT_OK -> {
Log.d(TAG, "Update success")
}
RESULT_CANCELED -> {
Log.d(TAG, "Update cancelled")
}
ActivityResult.RESULT_IN_APP_UPDATE_FAILED -> {
Log.d(TAG, "Update failed")
}
}
}
}
}
I faced this issue and after 2 days I added
android:launchMode="singleTask"
to the launcher Activity And I used
ProcessPhoenix.triggerRebirth(this)
From ProcessPhoenix library And then the app restarted after updating.
I'am trying to use rxBilling for in app purchases on my android app. library found here : https://github.com/betterme-dev/RxBilling
i manage to implemente it like this :
private fun launchBilling(subscription: Boolean) {
val sku = "com.app.subscription"
disposable.add(rxBilling.launchFlow(
this, BillingFlowParams.newBuilder()
.setSku(sku)
.setType(BillingClient.SkuType.SUBS)
.build()
)
.subscribe({
}, {
it.message?.let { msg -> unknownError(0, msg) }
})
)
}`
This is working perfectly, i pushed my app in internal test and i tried to subscribe, it's worked and i verified in my google play console that my subscription was taken into account.
The problem is that i want to get information of the purchase like date and transaction id. So i followed the guideline and implemented a disposable in the on start method :
override fun onStart() {
super.onStart()
println("onstrat")
disposable.add(
rxBilling.observeUpdates()
.subscribe({
println("here")
it.purchases.forEach { item ->
println("rxbillingstart")
println(item.toString())
println(item)
println(item.sku)
purchase(item)
}
}, {
togglePurchaseProgress(false)
it.message?.let { msg -> unknownError(0, msg) }
})
)
}
And for the implementation of the rxbilling and disposable in the on create method :
private lateinit var rxBilling: RxBilling
private lateinit var rxBillingFlow: RxBillingFlow
private val disposable = CompositeDisposable()
rxBilling = RxBillingImpl(BillingClientFactory(applicationContext))
rxBillingFlow = RxBillingFlow(applicationContext, BillingServiceFactory(this))
lifecycle.addObserver(BillingConnectionManager(rxBilling))
lifecycle.addObserver(BillingConnectionManager(rxBillingFlow))
The purchase methode is juste here to print item.orderId date ... but it's never called. Also my first print "onstrat" in the onStart method is called but all other print in the observable.subscribe are never called. Do I miss something? i don't get why i can't get subsciption informations
I found out that RxBilling is no longer maintained, so i used standard android billing client found here : https://developer.android.com/google/play/billing/integrate .But don't forget to add to your manifest :
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.vending.BILLING"/>
Then implemente those interface in your activity : PurchasesUpdatedListener, SkuDetailsResponseListener and set up the billing client variable : private lateinit var billingClient : BillingClient . Also it was unclear to me at first but sku is the product id you set up on googleplay console.
private fun buy(){
billingClient = BillingClient.newBuilder(this)
.setListener(this)
.enablePendingPurchases()
.build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
val skuList = ArrayList<String>()
skuList.add("premium_upgrade")
skuList.add("com.yourappname.subscription")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS)
billingClient.querySkuDetailsAsync(params.build(), this#DetailsActivity)
}
}
override fun onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})
}
Set up the skudetails you are searching for like this, then get the response here :
override fun onSkuDetailsResponse(responseCode: BillingResult, skuDetailsList: MutableList<SkuDetails>?) {
if (responseCode.responseCode != BillingClient.BillingResponseCode.OK) {
Log.w("LOG_TAG", "SkuDetails query failed with response: $responseCode")
} else {
Log.d("LOG_TAG", "SkuDetails query responded with success. List: $skuDetailsList")
if (skuDetailsList != null) {
for (skuDetails in skuDetailsList) {
var sku = skuDetails.getSku ()
var price = skuDetails.getPrice ()
var params = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();
if (sku == "com.yourappname.subscription") {
billingClient.launchBillingFlow(this, params);
}
}
}
}
}
This mean that if i found the right sku i lauchBillingflow -> i start the process of paying. Then you get the result on the payement here :
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: MutableList<Purchase>?) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && purchases != null) {
for (purchase in purchases) {
purchase(1, purchase)
}
} else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
} else {
// Handle any other error codes.
}
}
You can here get the result on your purchase such as purchaseTime, orderId, purchaseToken, and then my function purchase send the purchaseToken to an internal server to verify the transaction.
Hope it's will help some of you.
I'm working on an app which support subscription method my project is working completely fine and now I'm testing my app but the problem which struggling alot how to handle process if user unsubscribed and his subscription time expired and also what to know litle bit about aknowledge with no consumable and if user user unsubcribed in trial days or user unsubscribed in his validity period.
here is the code where purchase will get process
it will be called after query of skus where
i process method like purchased or pending purchased.....
.......
private fun processPurchases(purchasesResult: Set<Purchase>) =
CoroutineScope(Job() + Dispatchers.IO).launch {
// Log.d(LOG_TAG, "processPurchases called")
val validPurchases = HashSet<Purchase>(purchasesResult.size)
// Log.d(LOG_TAG, "processPurchases newBatch content $purchasesResult")
purchasesResult.forEach { purchase ->
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
// subscriptionPrefs.setSubscriptionValue(true)
if(purchase.sku==PlayBillingUtils.MONTHLY_PACKAGE){
subscriptionPurchased.postValue("you have successfully subscribed to monthly package")
subscriptionPrefs.setSubscriptionValue(false)
}
else if (purchase.sku == PlayBillingUtils.THREE_MONTH_PACKAGE){
purchasingMutableLiveData.postValue("you have sucessfully subscribed to 3 month package")
subscriptionPrefs.setSubscriptionValue(false)
}
if (isSignatureValid(purchase)) {
validPurchases.add(purchase) }
} else if (purchase.purchaseState == Purchase.PurchaseState.PENDING) {
purchasingMutableLiveData.postValue("Purchase Pending")
}
}
// here the token get acknowledge
acknowledgeNonConsumablePurchasesAsync(purchasesResult.toList())
}
Purchase all purchase Update will be invoked here but there is no method which will handle future call like when user unsubscribed or time expired want to know how to solve this problem
override fun onPurchasesUpdated(billingResult: BillingResult?, purchasemutableList: MutableList<Purchase>?) {
billingResult?.let {
when (billingResult.responseCode) {
BillingClient.BillingResponseCode.OK -> {
// will handle server verification, consumables, and updating the local cache
purchasemutableList?.apply { processPurchases(this.toSet()) }
}
BillingClient.BillingResponseCode.ITEM_NOT_OWNED -> {
subscriptionPrefs.setSubscriptionValue(false)
}
BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED -> {
// item already owned? call queryPurchasesAsync to verify and process all such items
println( billingResult.debugMessage)
subscriptionPrefs.setSubscriptionValue(true)
purchasingMutableLiveData.postValue("Item Already owned , enjoy ")
queryPurchasesAsync()
}
BillingClient.BillingResponseCode.SERVICE_DISCONNECTED -> {
purchasingMutableLiveData.postValue("Service Disconnected")
connectToPlayBillingService()
}
BillingClient.BillingResponseCode.ITEM_NOT_OWNED->{
purchasingMutableLiveData.postValue("Service Disconnected")
}
BillingClient.BillingResponseCode.SERVICE_TIMEOUT->{
purchasingMutableLiveData.postValue("Service Time Out try again")
}
BillingClient.BillingResponseCode.USER_CANCELED->{
subscriptionPrefs.setSubscriptionValue(false)
purchasingMutableLiveData.postValue("service is cancelled")
}
else -> {
println(billingResult.debugMessage)
}
}}
}
here i am passing subscription is aknowledge
private fun acknowledgeNonConsumablePurchasesAsync(nonConsumables: List<Purchase>) {
nonConsumables.forEach { purchase ->
val params = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase
.purchaseToken).build()
playstoreBillingCLient.acknowledgePurchase(params) { billingResult ->
when (billingResult.responseCode) {
BillingClient.BillingResponseCode.OK -> {
println("acknowledged")
}
else ->
println( "acknowledgeNonConsumablePurchasesAsync response is ${billingResult.debugMessage}")
}
}
}
}