From aa06c8aaed0aa7c878a4910ec38052ee623e600a Mon Sep 17 00:00:00 2001 From: Jonas Lochmann Date: Mon, 9 May 2022 02:00:00 +0200 Subject: [PATCH] Update google play billing library --- app/build.gradle | 3 +- .../ui/payment/ActivityPurchaseModel.kt | 50 ++++++++++----- .../android/ui/payment/PurchaseModel.kt | 6 +- .../android/ui/payment/StayAwesomeModel.kt | 10 +-- .../com/android/billingclient/api/Mocks.kt | 62 ++++++++++++------- 5 files changed, 80 insertions(+), 51 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index fa117ad..f64217c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -200,8 +200,7 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp-tls:4.9.3' implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3' - googleApiImplementation "com.android.billingclient:billing:4.1.0" - googleApiImplementation "com.android.billingclient:billing-ktx:4.1.0" + googleApiImplementation "com.android.billingclient:billing-ktx:5.0.0" implementation('io.socket:socket.io-client:2.0.0') { exclude group: 'org.json', module: 'json' diff --git a/app/src/main/java/io/timelimit/android/ui/payment/ActivityPurchaseModel.kt b/app/src/main/java/io/timelimit/android/ui/payment/ActivityPurchaseModel.kt index 81e50cf..8b13853 100644 --- a/app/src/main/java/io/timelimit/android/ui/payment/ActivityPurchaseModel.kt +++ b/app/src/main/java/io/timelimit/android/ui/payment/ActivityPurchaseModel.kt @@ -1,5 +1,5 @@ /* - * TimeLimit Copyright 2019 - 2021 Jonas Lochmann + * TimeLimit Copyright 2019 - 2022 Jonas Lochmann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -123,12 +123,16 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat } } - suspend fun querySkus(skuIds: List): List = initAndUseClient { client -> - val (billingResult, data) = client.querySkuDetails( - SkuDetailsParams.newBuilder() - .setSkusList(skuIds) - .setType(BillingClient.SkuType.INAPP) + suspend fun queryProducts(productIds: List): List = initAndUseClient { client -> + val (billingResult, data) = client.queryProductDetails( + QueryProductDetailsParams.newBuilder() + .setProductList(productIds.map { skuId -> + QueryProductDetailsParams.Product.newBuilder() + .setProductId(skuId) + .setProductType(BillingClient.ProductType.INAPP) .build() + }) + .build() ) billingResult.assertSuccess() @@ -137,7 +141,11 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat } suspend fun queryPurchases() = initAndUseClient { client -> - val response = client.queryPurchasesAsync(BillingClient.SkuType.INAPP) + val response = client.queryPurchasesAsync( + QueryPurchasesParams.newBuilder() + .setProductType(BillingClient.ProductType.INAPP) + .build() + ) response.billingResult.assertSuccess() @@ -153,7 +161,11 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat try { initAndUseClient { client -> - val result = client.queryPurchasesAsync(BillingClient.SkuType.INAPP) + val result = client.queryPurchasesAsync( + QueryPurchasesParams.newBuilder() + .setProductType(BillingClient.ProductType.INAPP) + .build() + ) result.billingResult.assertSuccess() @@ -223,7 +235,7 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat Log.d(LOG_TAG, "handlePurchase($purchase)") } - val sku = purchase.skus.single() + val sku = purchase.products.single() if (PurchaseIds.SAL_SKUS.contains(sku)) { // just acknowledge @@ -262,14 +274,14 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat } } - fun startPurchase(sku: String, checkAtBackend: Boolean, activity: Activity) { + fun startPurchase(productId: String, checkAtBackend: Boolean, activity: Activity) { runAsync { try { - val skuDetails = querySkus(listOf(sku)).single() + val productDetails = queryProducts(listOf(productId)).single() - if (skuDetails.sku != sku) throw IllegalStateException() + if (productDetails.productId != productId) throw IllegalStateException() - startPurchase(skuDetails, checkAtBackend, activity) + startPurchase(productDetails, checkAtBackend, activity) } catch (ex: Exception) { if (BuildConfig.DEBUG) { Log.d(LOG_TAG, "could not start purchase", ex) @@ -280,7 +292,7 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat } } - fun startPurchase(skuDetails: SkuDetails, checkAtBackend: Boolean, activity: Activity) { + private fun startPurchase(productDetails: ProductDetails, checkAtBackend: Boolean, activity: Activity) { runAsync { initAndUseClient { client -> try { @@ -299,10 +311,14 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat } client.launchBillingFlow( - activity, - BillingFlowParams.newBuilder() - .setSkuDetails(skuDetails) + activity, + BillingFlowParams.newBuilder() + .setProductDetailsParamsList(listOf( + BillingFlowParams.ProductDetailsParams.newBuilder() + .setProductDetails(productDetails) .build() + )) + .build() ).assertSuccess() } catch (ex: Exception) { if (BuildConfig.DEBUG) { diff --git a/app/src/main/java/io/timelimit/android/ui/payment/PurchaseModel.kt b/app/src/main/java/io/timelimit/android/ui/payment/PurchaseModel.kt index a42739e..c0bb82e 100644 --- a/app/src/main/java/io/timelimit/android/ui/payment/PurchaseModel.kt +++ b/app/src/main/java/io/timelimit/android/ui/payment/PurchaseModel.kt @@ -62,11 +62,11 @@ class PurchaseModel(application: Application): AndroidViewModel(application) { if (canDoPurchase.publicKey?.contentEquals(Base64.decode(BuildConfig.googlePlayKey, 0)) == false) { statusInternal.value = PurchaseFragmentServerHasDifferentPublicKey } else { - val skus = activityPurchaseModel.querySkus(PurchaseIds.BUY_SKUS) + val skus = activityPurchaseModel.queryProducts(PurchaseIds.BUY_SKUS) statusInternal.value = PurchaseFragmentReady( - monthPrice = skus.find { it.sku == PurchaseIds.SKU_MONTH }?.price.toString(), - yearPrice = skus.find { it.sku == PurchaseIds.SKU_YEAR }?.price.toString() + monthPrice = skus.find { it.productId == PurchaseIds.SKU_MONTH }?.oneTimePurchaseOfferDetails?.formattedPrice.toString(), + yearPrice = skus.find { it.productId == PurchaseIds.SKU_YEAR }?.oneTimePurchaseOfferDetails?.formattedPrice.toString() ) } } else if (canDoPurchase == CanDoPurchaseStatus.NotDueToOldPurchase) { diff --git a/app/src/main/java/io/timelimit/android/ui/payment/StayAwesomeModel.kt b/app/src/main/java/io/timelimit/android/ui/payment/StayAwesomeModel.kt index 3cb2396..52b5c93 100644 --- a/app/src/main/java/io/timelimit/android/ui/payment/StayAwesomeModel.kt +++ b/app/src/main/java/io/timelimit/android/ui/payment/StayAwesomeModel.kt @@ -1,5 +1,5 @@ /* - * TimeLimit Copyright 2019 - 2021 Jonas Lochmann + * TimeLimit Copyright 2019 - 2022 Jonas Lochmann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,18 +37,18 @@ class StayAwesomeModel(application: Application): AndroidViewModel(application) } try { - val skus = activityPurchaseModel.querySkus(PurchaseIds.SAL_SKUS) + val skus = activityPurchaseModel.queryProducts(PurchaseIds.SAL_SKUS) val purchases = activityPurchaseModel.queryPurchases() statusInternal.value = ReadyStayAwesomeStatus( PurchaseIds.SAL_SKUS.map { skuId -> - val sku = skus.find { it.sku == skuId } + val sku = skus.find { it.productId == skuId } StayAwesomeItem( id = skuId, title = sku?.description ?: skuId, - price = sku?.price ?: "???", - bought = purchases.find { purchase -> purchase.skus.find { sku -> sku == skuId } != null } != null + price = sku?.oneTimePurchaseOfferDetails?.formattedPrice.toString(), + bought = purchases.find { purchase -> purchase.products.find { sku -> sku == skuId } != null } != null ) } ) diff --git a/app/src/noGoogleApi/java/com/android/billingclient/api/Mocks.kt b/app/src/noGoogleApi/java/com/android/billingclient/api/Mocks.kt index aba32d8..660edaa 100644 --- a/app/src/noGoogleApi/java/com/android/billingclient/api/Mocks.kt +++ b/app/src/noGoogleApi/java/com/android/billingclient/api/Mocks.kt @@ -1,5 +1,5 @@ /* - * TimeLimit Copyright 2019 - 2021 Jonas Lochmann + * TimeLimit Copyright 2019 - 2022 Jonas Lochmann * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,20 +28,18 @@ object BillingClient { fun endConnection() {} - fun querySkuDetails(param: SkuDetailsParams) = QuerySkuDetailsResult.instance + fun queryProductDetails(param: QueryProductDetailsParams) = QueryProductDetailsResult.instance fun launchBillingFlow(activity: Activity, params: BillingFlowParams) = BillingResult fun acknowledgePurchase(params: AcknowledgePurchaseParams) = BillingResult fun consumePurchase(params: ConsumeParams) = BillingResult - suspend fun queryPurchasesAsync(type: String) = QueryPurchasesResult + suspend fun queryPurchasesAsync(request: QueryPurchasesParams) = QueryPurchasesResult object BillingResponseCode { const val OK = 0 const val ERR = 1 } - object SkuType { - const val INAPP = "" - } + enum class ProductType { INAPP } object Builder { fun enablePendingPurchases() = this @@ -55,26 +53,20 @@ object BillingResult { const val debugMessage = "only mock linked" } -object SkuDetails { - const val sku = "" - const val price = "" +object ProductDetails { + const val productId = "" const val description = "" -} + val oneTimePurchaseOfferDetails: OfferDetails? = OfferDetails -object SkuDetailsParams { - fun newBuilder() = Builder - - object Builder { - fun setSkusList(list: List) = this - fun setType(type: String) = this - fun build() = SkuDetailsParams + object OfferDetails { + const val formattedPrice = "" } } object Purchase { const val purchaseState = PurchaseState.PURCHASED const val isAcknowledged = true - val skus = listOf("") + val products = emptyList() const val purchaseToken = "" const val originalJson = "" const val signature = "" @@ -103,11 +95,14 @@ object ConsumeParams { } object BillingFlowParams { - fun newBuilder() = Builder + fun newBuilder() = this + fun setProductDetailsParamsList(details: List) = this + fun build() = this - object Builder { - fun setSkuDetails(details: SkuDetails) = this - fun build() = BillingFlowParams + object ProductDetailsParams { + fun newBuilder() = this + fun setProductDetails(details: ProductDetails) = this + fun build() = this } } @@ -116,9 +111,9 @@ object QueryPurchasesResult { val purchasesList: List = emptyList() } -data class QuerySkuDetailsResult(val billingResult: BillingResult, val details: List?) { +data class QueryProductDetailsResult(val billingResult: BillingResult, val details: List?) { companion object { - val instance = QuerySkuDetailsResult(BillingResult, emptyList()) + val instance = QueryProductDetailsResult(BillingResult, emptyList()) } } @@ -129,4 +124,23 @@ interface BillingClientStateListener { interface PurchasesUpdatedListener { fun onPurchasesUpdated(p0: BillingResult, p1: MutableList?) +} + +object QueryProductDetailsParams { + fun newBuilder() = this + fun setProductList(list: List) = this + fun build() = this + + object Product { + fun newBuilder() = this + fun setProductId(id: String) = this + fun setProductType(type: BillingClient.ProductType) = this + fun build() = this + } +} + +object QueryPurchasesParams { + fun newBuilder() = this + fun setProductType(type: BillingClient.ProductType) = this + fun build() = this } \ No newline at end of file