From 70364fbbfa7d13dbb9b939a5bfb3038dbd5737f9 Mon Sep 17 00:00:00 2001 From: Kamo Spertsyan Date: Fri, 11 Oct 2024 12:37:56 +0300 Subject: [PATCH 1/3] Added purchase callback with quantity for inapp purchases. --- .../sdk/internal/QProductCenterManager.kt | 17 +++++---- .../sdk/internal/QonversionInternal.kt | 37 ++++++++++++++++--- .../sdk/listeners/QonversionCallback.kt | 4 ++ 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/sdk/src/main/java/com/qonversion/android/sdk/internal/QProductCenterManager.kt b/sdk/src/main/java/com/qonversion/android/sdk/internal/QProductCenterManager.kt index 30b3f08f..b101416e 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/internal/QProductCenterManager.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/internal/QProductCenterManager.kt @@ -45,6 +45,7 @@ import com.qonversion.android.sdk.internal.services.QUserInfoService import com.qonversion.android.sdk.internal.storage.LaunchResultCacheWrapper import com.qonversion.android.sdk.internal.storage.PurchasesCache import com.qonversion.android.sdk.listeners.QEntitlementsUpdateListener +import com.qonversion.android.sdk.listeners.QonversionPurchaseCallback import com.qonversion.android.sdk.listeners.QonversionUserCallback import kotlin.math.min import java.util.Date @@ -79,7 +80,7 @@ internal class QProductCenterManager internal constructor( private var productsCallbacks = mutableListOf() private var entitlementCallbacks = mutableListOf() - private var purchasingCallbacks = mutableMapOf() + private var purchasingCallbacks = mutableMapOf() private var restoreCallbacks = mutableListOf() private var processingPartnersIdentityId: String? = null @@ -292,7 +293,7 @@ internal class QProductCenterManager internal constructor( fun purchaseProduct( context: Activity, purchaseModel: PurchaseModelInternal, - callback: QonversionEntitlementsCallback + callback: QonversionPurchaseCallback ) { if (internalConfig.isAnalyticsMode) { logger.warn( @@ -318,7 +319,7 @@ internal class QProductCenterManager internal constructor( private fun tryToPurchase( context: Activity, purchaseModel: PurchaseModelInternal, - callback: QonversionEntitlementsCallback + callback: QonversionPurchaseCallback ) { val products = launchResultCache.getActualProducts() ?: run { callback.onError(launchError ?: QonversionError(QonversionErrorCode.LaunchError)) @@ -337,7 +338,7 @@ internal class QProductCenterManager internal constructor( private fun processPurchase( context: Activity, purchaseModel: PurchaseModelInternalEnriched, - callback: QonversionEntitlementsCallback + callback: QonversionPurchaseCallback ) { if (purchaseModel.product.storeID == null) { callback.onError(QonversionError(QonversionErrorCode.ProductNotFound)) @@ -477,7 +478,7 @@ internal class QProductCenterManager internal constructor( private fun calculatePurchasePermissionsLocally( purchase: Purchase, - purchaseCallback: QonversionEntitlementsCallback?, + purchaseCallback: QonversionPurchaseCallback?, purchaseError: QonversionError ) { val products = launchResultCache.getActualProducts() ?: run { @@ -505,11 +506,11 @@ internal class QProductCenterManager internal constructor( purchasedProduct, productPermissions ) - purchaseCallback?.onSuccess(permissions.toEntitlementsMap()) + purchaseCallback?.onSuccess(permissions.toEntitlementsMap(), purchase.quantity) } private fun failLocallyGrantingPurchasePermissionsWithError( - callback: QonversionEntitlementsCallback?, + callback: QonversionPurchaseCallback?, error: QonversionError ) { launchResultCache.clearPermissionsCache() @@ -999,7 +1000,7 @@ internal class QProductCenterManager internal constructor( val entitlements = launchResult.permissions.toEntitlementsMap() removePurchaseOptions(product?.storeID) - purchaseCallback?.onSuccess(entitlements) ?: run { + purchaseCallback?.onSuccess(entitlements, purchase.quantity) ?: run { internalConfig.entitlementsUpdateListener?.onEntitlementsUpdated( entitlements ) diff --git a/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt b/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt index 9d7986f4..99809f8a 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt @@ -37,6 +37,7 @@ import com.qonversion.android.sdk.listeners.QonversionRemoteConfigCallback import com.qonversion.android.sdk.listeners.QonversionEligibilityCallback import com.qonversion.android.sdk.listeners.QonversionUserCallback import com.qonversion.android.sdk.listeners.QEntitlementsUpdateListener +import com.qonversion.android.sdk.listeners.QonversionPurchaseCallback import com.qonversion.android.sdk.listeners.QonversionRemoteConfigListCallback import com.qonversion.android.sdk.listeners.QonversionRemoteConfigurationAttachCallback import com.qonversion.android.sdk.listeners.QonversionUserPropertiesCallback @@ -157,6 +158,7 @@ internal class QonversionInternal( }) } + @Deprecated("Use the new purchase() method", replaceWith = ReplaceWith("purchase(context, TODO(\"pass product here\"), callback)")) override fun purchase( context: Activity, purchaseModel: QPurchaseModel, @@ -165,7 +167,7 @@ internal class QonversionInternal( productCenterManager.purchaseProduct( context, PurchaseModelInternal(purchaseModel), - mainEntitlementsCallback(callback) + mainPurchaseCallback(callback) ) } @@ -178,7 +180,7 @@ internal class QonversionInternal( productCenterManager.purchaseProduct( context, PurchaseModelInternal(product, options), - mainEntitlementsCallback(callback) + mainPurchaseCallback(callback) ) } @@ -190,7 +192,7 @@ internal class QonversionInternal( productCenterManager.purchaseProduct( context, PurchaseModelInternal(product), - mainEntitlementsCallback(callback) + mainPurchaseCallback(callback) ) } @@ -203,10 +205,11 @@ internal class QonversionInternal( productCenterManager.purchaseProduct( context, PurchaseModelInternal(product, options), - mainEntitlementsCallback(callback) + mainPurchaseCallback(callback) ) } + @Deprecated("Use the new updatePurchase() method", replaceWith = ReplaceWith("updatePurchase(context, TODO(\"pass product here\"), TODO(\"pass purchase options here\"), callback)")) override fun updatePurchase( context: Activity, purchaseUpdateModel: QPurchaseUpdateModel, @@ -215,7 +218,7 @@ internal class QonversionInternal( productCenterManager.purchaseProduct( context, PurchaseModelInternal(purchaseUpdateModel), - mainEntitlementsCallback(callback) + mainPurchaseCallback(callback) ) } @@ -395,6 +398,30 @@ internal class QonversionInternal( postToMainThread { callback.onError(error) } } + private fun mainPurchaseCallback(callback: QonversionEntitlementsCallback): QonversionPurchaseCallback { + val purchaseCallback = if (callback is QonversionPurchaseCallback) callback else object : QonversionPurchaseCallback { + override fun onSuccess(entitlements: Map) { + callback.onSuccess(entitlements) + } + + override fun onError(error: QonversionError) { + callback.onError(error) + } + } + + return object : QonversionPurchaseCallback { + override fun onSuccess(entitlements: Map, quantity: Int) { + postToMainThread { purchaseCallback.onSuccess(entitlements, quantity) } + } + + override fun onSuccess(entitlements: Map) = + postToMainThread { purchaseCallback.onSuccess(entitlements) } + + override fun onError(error: QonversionError) = + postToMainThread { purchaseCallback.onError(error) } + } + } + private fun mainUserCallback(callback: QonversionUserCallback): QonversionUserCallback = object : QonversionUserCallback { override fun onSuccess(user: QUser) = diff --git a/sdk/src/main/java/com/qonversion/android/sdk/listeners/QonversionCallback.kt b/sdk/src/main/java/com/qonversion/android/sdk/listeners/QonversionCallback.kt index 9520770d..a1bae23b 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/listeners/QonversionCallback.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/listeners/QonversionCallback.kt @@ -46,6 +46,10 @@ interface QonversionRemoteConfigurationAttachCallback { fun onError(error: QonversionError) } +interface QonversionPurchaseCallback : QonversionEntitlementsCallback { + fun onSuccess(entitlements: Map, quantity: Int) = onSuccess(entitlements) +} + interface QonversionEntitlementsCallback { fun onSuccess(entitlements: Map) fun onError(error: QonversionError) From 9a95bdf3586e7671ee608f69bf94b950369a3571 Mon Sep 17 00:00:00 2001 From: Kamo Spertsyan Date: Fri, 11 Oct 2024 15:43:30 +0300 Subject: [PATCH 2/3] Changed quantity with complete purchase. --- .../qonversion/android/sdk/internal/QProductCenterManager.kt | 4 ++-- .../qonversion/android/sdk/internal/QonversionInternal.kt | 5 +++-- .../qonversion/android/sdk/listeners/QonversionCallback.kt | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sdk/src/main/java/com/qonversion/android/sdk/internal/QProductCenterManager.kt b/sdk/src/main/java/com/qonversion/android/sdk/internal/QProductCenterManager.kt index b101416e..d7e32794 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/internal/QProductCenterManager.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/internal/QProductCenterManager.kt @@ -506,7 +506,7 @@ internal class QProductCenterManager internal constructor( purchasedProduct, productPermissions ) - purchaseCallback?.onSuccess(permissions.toEntitlementsMap(), purchase.quantity) + purchaseCallback?.onSuccess(permissions.toEntitlementsMap(), purchase) } private fun failLocallyGrantingPurchasePermissionsWithError( @@ -1000,7 +1000,7 @@ internal class QProductCenterManager internal constructor( val entitlements = launchResult.permissions.toEntitlementsMap() removePurchaseOptions(product?.storeID) - purchaseCallback?.onSuccess(entitlements, purchase.quantity) ?: run { + purchaseCallback?.onSuccess(entitlements, purchase) ?: run { internalConfig.entitlementsUpdateListener?.onEntitlementsUpdated( entitlements ) diff --git a/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt b/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt index 99809f8a..d995fc4d 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt @@ -5,6 +5,7 @@ import android.app.Application import android.os.Handler import android.os.Looper import androidx.lifecycle.ProcessLifecycleOwner +import com.android.billingclient.api.Purchase import com.qonversion.android.sdk.Qonversion import com.qonversion.android.sdk.automations.internal.QAutomationsManager import com.qonversion.android.sdk.dto.QAttributionProvider @@ -410,8 +411,8 @@ internal class QonversionInternal( } return object : QonversionPurchaseCallback { - override fun onSuccess(entitlements: Map, quantity: Int) { - postToMainThread { purchaseCallback.onSuccess(entitlements, quantity) } + override fun onSuccess(entitlements: Map, purchase: Purchase) { + postToMainThread { purchaseCallback.onSuccess(entitlements, purchase) } } override fun onSuccess(entitlements: Map) = diff --git a/sdk/src/main/java/com/qonversion/android/sdk/listeners/QonversionCallback.kt b/sdk/src/main/java/com/qonversion/android/sdk/listeners/QonversionCallback.kt index a1bae23b..628c8ea9 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/listeners/QonversionCallback.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/listeners/QonversionCallback.kt @@ -1,5 +1,6 @@ package com.qonversion.android.sdk.listeners +import com.android.billingclient.api.Purchase import com.qonversion.android.sdk.dto.entitlements.QEntitlement import com.qonversion.android.sdk.dto.QRemoteConfig import com.qonversion.android.sdk.dto.QRemoteConfigList @@ -47,7 +48,7 @@ interface QonversionRemoteConfigurationAttachCallback { } interface QonversionPurchaseCallback : QonversionEntitlementsCallback { - fun onSuccess(entitlements: Map, quantity: Int) = onSuccess(entitlements) + fun onSuccess(entitlements: Map, purchase: Purchase) = onSuccess(entitlements) } interface QonversionEntitlementsCallback { From c1902ebeadea18863f97e493ed91a6338bbcd0f5 Mon Sep 17 00:00:00 2001 From: Kamo Spertsyan Date: Fri, 11 Oct 2024 15:46:00 +0300 Subject: [PATCH 3/3] Detekt fixes --- config/detekt/baseline.xml | 8 ++++++-- .../android/sdk/internal/QonversionInternal.kt | 16 ++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index a4a0a429..87bbe330 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -118,6 +118,8 @@ MaxLineLength:QonversionConfig.kt$QonversionConfig.Builder$* MaxLineLength:QonversionError.kt$QonversionErrorCode$* MaxLineLength:QonversionError.kt$QonversionErrorCode$RemoteConfigurationNotAvailable : QonversionErrorCode + MaxLineLength:QonversionInternal.kt$QonversionInternal$@Deprecated("Use the new purchase() method", replaceWith = ReplaceWith("purchase(context, TODO(\"pass product here\"), callback)")) + MaxLineLength:QonversionInternal.kt$QonversionInternal$@Deprecated("Use the new updatePurchase() method", replaceWith = ReplaceWith("updatePurchase(context, TODO(\"pass product here\"), TODO(\"pass purchase options here\"), callback)")) MaxLineLength:QonversionRepositoryIntegrationTest.kt$QonversionRepositoryIntegrationTest$"""HTTP status code=400, data={"message":"Invalid access token received","code":10003,"status":400,"extra":[]}. """ MaxLineLength:QonversionRepositoryIntegrationTest.kt$QonversionRepositoryIntegrationTest$"lcbfeigohklhpdgmpildjabg.AO-J1OyV-EE2bKGqDcRCvqjZ2NI1uHDRuvonRn5RorP6LNsyK7yHK8FaFlXp6bjTEX3-4JvZKtbY_bpquKBfux09Mfkx05M9YGZsfsr5BJk74r719m77Oyo" MaxLineLength:QonversionRepositoryIntegrationTest.kt$QonversionRepositoryIntegrationTest$"lgeigljfpmeoddkcebkcepjc.AO-J1Oy305qZj99jXTPEVBN8UZGoYAtjDLj4uTjRQvUFaG0vie-nr6VBlN0qnNDMU8eJR-sI7o3CwQyMOEHKl8eJsoQ86KSFzxKBR07PSpHLI_o7agXhNKY" @@ -154,11 +156,13 @@ MaximumLineLength:com.qonversion.android.sdk.internal.OutagerIntegrationTest.kt:214 MaximumLineLength:com.qonversion.android.sdk.internal.OutagerIntegrationTest.kt:371 MaximumLineLength:com.qonversion.android.sdk.internal.OutagerIntegrationTest.kt:90 - MaximumLineLength:com.qonversion.android.sdk.internal.QProductCenterManager.kt:332 + MaximumLineLength:com.qonversion.android.sdk.internal.QProductCenterManager.kt:333 MaximumLineLength:com.qonversion.android.sdk.internal.QProductCenterManagerTest.kt:152 MaximumLineLength:com.qonversion.android.sdk.internal.QProductCenterManagerTest.kt:153 MaximumLineLength:com.qonversion.android.sdk.internal.QRemoteConfigManager.kt:225 MaximumLineLength:com.qonversion.android.sdk.internal.QUserPropertiesManagerTest.kt:178 + MaximumLineLength:com.qonversion.android.sdk.internal.QonversionInternal.kt:162 + MaximumLineLength:com.qonversion.android.sdk.internal.QonversionInternal.kt:213 MaximumLineLength:com.qonversion.android.sdk.internal.QonversionRepositoryIntegrationTest.kt:287 MaximumLineLength:com.qonversion.android.sdk.internal.QonversionRepositoryIntegrationTest.kt:356 MaximumLineLength:com.qonversion.android.sdk.internal.QonversionRepositoryIntegrationTest.kt:878 @@ -243,7 +247,7 @@ ReturnCount:QExceptionManager.kt$QExceptionManager$private fun getContentOfCrashReport(filename: String): CrashRequest.ExceptionInfo? ReturnCount:QProductCenterManager.kt$QProductCenterManager$@Synchronized private fun executeProductsBlocks(loadStoreProductsError: QonversionError? = null) ReturnCount:QProductCenterManager.kt$QProductCenterManager$fun identify(identityId: String, callback: QonversionUserCallback? = null) - ReturnCount:QProductCenterManager.kt$QProductCenterManager$private fun calculatePurchasePermissionsLocally( purchase: Purchase, purchaseCallback: QonversionEntitlementsCallback?, purchaseError: QonversionError ) + ReturnCount:QProductCenterManager.kt$QProductCenterManager$private fun calculatePurchasePermissionsLocally( purchase: Purchase, purchaseCallback: QonversionPurchaseCallback?, purchaseError: QonversionError ) ReturnCount:ScreenPresenter.kt$ScreenPresenter$override fun shouldOverrideUrlLoading(url: String?): Boolean SpacingAroundColon:com.qonversion.android.sdk.internal.requests.ProviderDataRequestTest.kt:45 SpacingAroundCurly:com.qonversion.android.sdk.automations.internal.QAutomationsManagerTest.kt:254 diff --git a/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt b/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt index d995fc4d..f79eaac7 100644 --- a/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt +++ b/sdk/src/main/java/com/qonversion/android/sdk/internal/QonversionInternal.kt @@ -400,13 +400,17 @@ internal class QonversionInternal( } private fun mainPurchaseCallback(callback: QonversionEntitlementsCallback): QonversionPurchaseCallback { - val purchaseCallback = if (callback is QonversionPurchaseCallback) callback else object : QonversionPurchaseCallback { - override fun onSuccess(entitlements: Map) { - callback.onSuccess(entitlements) - } + val purchaseCallback = if (callback is QonversionPurchaseCallback) { + callback + } else { + object : QonversionPurchaseCallback { + override fun onSuccess(entitlements: Map) { + callback.onSuccess(entitlements) + } - override fun onError(error: QonversionError) { - callback.onError(error) + override fun onError(error: QonversionError) { + callback.onError(error) + } } }