diff --git a/app/build.gradle b/app/build.gradle index 790b081..87ef2f8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,7 +35,7 @@ android { dependencies { - implementation 'androidx.core:core-ktx:1.12.0' + implementation 'androidx.core:core-ktx:1.13.0' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.11.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' diff --git a/billing/build.gradle b/billing/build.gradle index 2122a11..6bba532 100644 --- a/billing/build.gradle +++ b/billing/build.gradle @@ -29,11 +29,11 @@ android { dependencies { - implementation 'androidx.core:core-ktx:1.12.0' + implementation 'androidx.core:core-ktx:1.13.0' implementation 'androidx.appcompat:appcompat:1.6.1' // Google Play Billing - implementation "com.android.billingclient:billing-ktx:6.1.0" + implementation "com.android.billingclient:billing-ktx:6.2.1" // LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.7.0" diff --git a/billing/src/main/java/com/hypersoft/billing/asd.kt b/billing/src/main/java/com/hypersoft/billing/asd.kt deleted file mode 100644 index e8a0039..0000000 --- a/billing/src/main/java/com/hypersoft/billing/asd.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.hypersoft.billing - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.suspendCancellableCoroutine -import kotlin.coroutines.resume - -/** - * @Author: SOHAIB AHMED - * @Date: 14/03/2024 - * @Accounts - * -> https://github.com/epegasus - * -> https://stackoverflow.com/users/20440272/sohaib-ahmed - */ - - -fun main() { - runBlocking { - for (i in 0..50) { - val data = fetchData(i) - println(data) - } - } -} - -suspend fun fetchData(index: Int): String { - println("Processing : $index") - return suspendCancellableCoroutine { continuation -> - CoroutineScope(Dispatchers.IO).launch { - delay(1000) - if (continuation.isActive) { - continuation.resume("Result # $index") - } - } - } -} \ No newline at end of file diff --git a/billing/src/main/java/com/hypersoft/billing/repository/BillingRepository.kt b/billing/src/main/java/com/hypersoft/billing/repository/BillingRepository.kt index be687e2..cb72091 100644 --- a/billing/src/main/java/com/hypersoft/billing/repository/BillingRepository.kt +++ b/billing/src/main/java/com/hypersoft/billing/repository/BillingRepository.kt @@ -265,16 +265,25 @@ open class BillingRepository(context: Context) { val resultList = ArrayList() val completePurchaseList = purchases.map { purchase -> + Log.d(TAG, "BillingRepository: Purchase: $purchases") val productParams = queryUtils.getPurchaseParams(userQueryList, purchase.products) val productDetailsList = queryUtils.queryProductDetailsAsync(productParams) CompletePurchase(purchase, productDetailsList) } completePurchaseList.forEach { completePurchase -> + Log.d(TAG, "BillingRepository: CompletePurchase: $completePurchase") + completePurchase.productDetailList.forEach { productDetails -> val productType = if (productDetails.productType == BillingClient.ProductType.INAPP) ProductType.inapp else ProductType.subs - val planId = queryUtils.getPlanId(productDetails.subscriptionOfferDetails) - val planTitle = productDetails.subscriptionOfferDetails?.get(0)?.let { queryUtils.getPlanTitle(it) } ?: "" + val splitList = completePurchase.purchase.accountIdentifiers?.obfuscatedAccountId?.split("_") ?: emptyList() + val planId = if (splitList.isNotEmpty() && splitList.size >= 2) { + splitList[1] + } else { + "" + } + val offerDetails = productDetails.subscriptionOfferDetails?.find { it.basePlanId == planId } + val planTitle = offerDetails?.let { queryUtils.getPlanTitle(it) } ?: "" val purchaseDetail = PurchaseDetail( productId = productDetails.productId, @@ -431,7 +440,7 @@ open class BillingRepository(context: Context) { && it.productDetail.productType == ProductType.inapp } queryProductDetail?.let { - launchFlow(activity = activity!!, it.productDetails, offerToken = null) + launchFlow(activity = activity!!, "", it.productDetails, offerToken = null) } ?: run { Result.setResultState(ResultState.CONSOLE_PRODUCTS_IN_APP_NOT_EXIST) onPurchaseListener.onPurchaseResult(false, message = ResultState.CONSOLE_PRODUCTS_IN_APP_NOT_EXIST.message) @@ -459,16 +468,33 @@ open class BillingRepository(context: Context) { return } - launchFlow(activity = activity!!, queryProductDetail.productDetails, offerToken = queryProductDetail.offerDetails.offerToken) + launchFlow(activity = activity!!, planId, queryProductDetail.productDetails, offerToken = queryProductDetail.offerDetails.offerToken) } - private fun launchFlow(activity: Activity, productDetails: ProductDetails, offerToken: String?) { + private fun launchFlow(activity: Activity, planId: String, productDetails: ProductDetails, offerToken: String?) { Log.i(TAG, "launchFlow: Product Details about to be purchase: $productDetails") val paramsList = when (offerToken == null) { true -> listOf(BillingFlowParams.ProductDetailsParams.newBuilder().setProductDetails(productDetails).build()) false -> listOf(BillingFlowParams.ProductDetailsParams.newBuilder().setProductDetails(productDetails).setOfferToken(offerToken).build()) } - val flowParams = BillingFlowParams.newBuilder().setProductDetailsParamsList(paramsList).build() + + val timeStamp = "${System.currentTimeMillis()}" + val temp = "${timeStamp}_$planId" + + val flowParams = if (planId.isEmpty()) { + BillingFlowParams + .newBuilder() + .setProductDetailsParamsList(paramsList) + .build() + } else { + BillingFlowParams + .newBuilder() + .setProductDetailsParamsList(paramsList) + .setObfuscatedAccountId(temp) + .setObfuscatedProfileId(timeStamp) + .build() + } + billingClient.launchBillingFlow(activity, flowParams) Result.setResultState(ResultState.LAUNCHING_FLOW_INVOCATION_SUCCESSFULLY) } @@ -525,11 +551,24 @@ open class BillingRepository(context: Context) { .setSubscriptionReplacementMode(BillingFlowParams.SubscriptionUpdateParams.ReplacementMode.CHARGE_FULL_PRICE) .build() - val flowParams = - BillingFlowParams.newBuilder() + val timeStamp = "${System.currentTimeMillis()}" + val temp = "${timeStamp}_$planId" + + val flowParams = if (planId.isEmpty()) { + BillingFlowParams + .newBuilder() .setProductDetailsParamsList(paramsList) .setSubscriptionUpdateParams(updateParams) .build() + } else { + BillingFlowParams + .newBuilder() + .setProductDetailsParamsList(paramsList) + .setSubscriptionUpdateParams(updateParams) + .setObfuscatedAccountId(temp) + .setObfuscatedProfileId(timeStamp) + .build() + } billingClient.launchBillingFlow(activity!!, flowParams) Result.setResultState(ResultState.LAUNCHING_FLOW_INVOCATION_SUCCESSFULLY) diff --git a/billing/src/main/java/com/hypersoft/billing/utils/QueryUtils.kt b/billing/src/main/java/com/hypersoft/billing/utils/QueryUtils.kt index f03831e..5492a91 100644 --- a/billing/src/main/java/com/hypersoft/billing/utils/QueryUtils.kt +++ b/billing/src/main/java/com/hypersoft/billing/utils/QueryUtils.kt @@ -96,7 +96,7 @@ internal class QueryUtils(private val billingClient: BillingClient) { * @param subscriptionOfferDetailList: find reliable base plan id for a product * * @return base plan title according to billingPeriod - * @see [com.hypersoft.billing.latest.dataClasses.ProductDetail] + * @see [com.hypersoft.billing.dataClasses.ProductDetail] */ fun getPlanTitle(subscriptionOfferDetailList: ProductDetails.SubscriptionOfferDetails): String {