Skip to content

Commit

Permalink
Update to BillingClient 4.0 (#321)
Browse files Browse the repository at this point in the history
  • Loading branch information
vegaro committed Jun 7, 2021
1 parent 09dfd6f commit f6554bb
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 15 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Expand Up @@ -2,7 +2,7 @@ buildscript {
ext.kotlinVersion = "1.4.10"
ext.compileVersion = 28
ext.minVersion = 14
ext.billingVersion = "3.0.2"
ext.billingVersion = "4.0.0"
ext.lifecycleVersion = "2.3.0-rc01"
repositories {
mavenCentral()
Expand Down
8 changes: 6 additions & 2 deletions common/src/main/java/com/revenuecat/purchases/common/utils.kt
Expand Up @@ -18,7 +18,9 @@ import java.util.Locale
const val MICROS_MULTIPLIER = 1_000_000

fun Purchase.toHumanReadableDescription() =
"${this.sku} ${this.orderId} ${this.purchaseToken}"
"skus: ${
this.skus.joinToString(prefix = "[", postfix = "]")
}, orderId: ${this.orderId}, purchaseToken: ${this.purchaseToken}"

fun Context.getLocale(): Locale? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Expand Down Expand Up @@ -100,7 +102,9 @@ fun BillingResult.toHumanReadableDescription() =
"DebugMessage: $debugMessage. ErrorCode: ${responseCode.getBillingResponseCodeName()}."

fun PurchaseHistoryRecord.toHumanReadableDescription() =
"${this.sku} ${this.purchaseTime} ${this.purchaseToken}"
"skus: ${
this.skus.joinToString(prefix = "[", postfix = "]")
}, purchaseTime: ${this.purchaseTime}, purchaseToken: ${this.purchaseToken}"

val Context.versionName: String?
get() = this.packageManager.getPackageInfo(this.packageName, 0).versionName
Expand Down
Expand Up @@ -191,10 +191,13 @@ class BillingWrapper(
.setSkuDetails(productDetails.skuDetails)
.apply {
replaceSkuInfo?.apply {
setOldSku(oldPurchase.sku, oldPurchase.purchaseToken)
prorationMode?.let { prorationMode ->
setReplaceSkusProrationMode(prorationMode)
val subscriptionUpdateParams = BillingFlowParams.SubscriptionUpdateParams.newBuilder().apply {
setOldSkuPurchaseToken(oldPurchase.purchaseToken)
prorationMode?.let { prorationMode ->
setReplaceSkusProrationMode(prorationMode)
}
}
setSubscriptionUpdateParams(subscriptionUpdateParams.build())
} ?: setObfuscatedAccountId(appUserID.sha256())
// only setObfuscatedAccountId for non-upgrade/downgrades until google issue is fixed:
// https://issuetracker.google.com/issues/155005449
Expand Down Expand Up @@ -415,9 +418,8 @@ class BillingWrapper(
queryPurchaseHistoryAsync(skuType) { result, purchasesList ->
if (result.isSuccessful()) {
val purchaseHistoryRecordWrapper =
purchasesList?.firstOrNull { sku == it.sku }?.let { purchaseHistoryRecord ->
purchaseHistoryRecord.toRevenueCatPurchaseDetails(productType)
}
purchasesList?.firstOrNull { it.skus.contains(sku) }
?.toRevenueCatPurchaseDetails(productType)

if (purchaseHistoryRecordWrapper != null) {
onCompletion(purchaseHistoryRecordWrapper)
Expand Down
@@ -0,0 +1,31 @@
package com.revenuecat.purchases.google

import com.android.billingclient.api.Purchase
import com.android.billingclient.api.PurchaseHistoryRecord
import com.revenuecat.purchases.common.LogIntent
import com.revenuecat.purchases.common.log
import com.revenuecat.purchases.strings.BillingStrings

/**
* **Important**: until multi-line subscriptions are released,
* we assume that there will be only a single sku in the purchase.
* https://android-developers.googleblog.com/2021/05/whats-new-in-google-play-2021.html
*/
val PurchaseHistoryRecord.sku: String
get() = skus[0].also {
if (skus.size > 0) {
log(LogIntent.GOOGLE_WARNING, BillingStrings.BILLING_PURCHASE_HISTORY_RECORD_MORE_THAN_ONE_SKU)
}
}

/**
* **Important**: until multi-line subscriptions are released,
* we assume that there will be only a single sku in the purchase.
* https://android-developers.googleblog.com/2021/05/whats-new-in-google-play-2021.html
*/
val Purchase.sku: String
get() = skus[0].also {
if (skus.size > 0) {
log(LogIntent.GOOGLE_WARNING, BillingStrings.BILLING_PURCHASE_MORE_THAN_ONE_SKU)
}
}
Expand Up @@ -271,6 +271,34 @@ class BillingWrapperTest {

@Test
fun properlySetsBillingFlowParams() {
mockkStatic(BillingFlowParams::class)
mockkStatic(BillingFlowParams.SubscriptionUpdateParams::class)

val mockBuilder = mockk<BillingFlowParams.Builder>(relaxed = true)
every {
BillingFlowParams.newBuilder()
} returns mockBuilder

val skuDetailsSlot = slot<SkuDetails>()
every {
mockBuilder.setSkuDetails(capture(skuDetailsSlot))
} returns mockBuilder

val mockSubscriptionUpdateParamsBuilder = mockk<BillingFlowParams.SubscriptionUpdateParams.Builder>(relaxed = true)
every {
BillingFlowParams.SubscriptionUpdateParams.newBuilder()
} returns mockSubscriptionUpdateParamsBuilder

val oldSkuPurchaseTokenSlot = slot<String>()
every {
mockSubscriptionUpdateParamsBuilder.setOldSkuPurchaseToken(capture(oldSkuPurchaseTokenSlot))
} returns mockSubscriptionUpdateParamsBuilder

val prorationModeSlot = slot<Int>()
every {
mockSubscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(capture(prorationModeSlot))
} returns mockSubscriptionUpdateParamsBuilder

val sku = "product_a"
@BillingClient.SkuType val skuType = BillingClient.SkuType.SUBS

Expand All @@ -282,12 +310,13 @@ class BillingWrapperTest {
every {
mockClient.launchBillingFlow(eq(activity), capture(slot))
} answers {
val params = slot.captured
assertThat(sku).isEqualTo(params.sku)
assertThat(skuType).isEqualTo(params.skuType)
assertThat(upgradeInfo.oldPurchase.sku).isEqualTo(params.oldSku)
assertThat(upgradeInfo.oldPurchase.purchaseToken).isEqualTo(params.oldSkuPurchaseToken)
assertThat(upgradeInfo.prorationMode).isEqualTo(params.replaceSkusProrationMode)
val capturedSkuDetails = skuDetailsSlot.captured

assertThat(sku).isEqualTo(capturedSkuDetails.sku)
assertThat(skuType).isEqualTo(capturedSkuDetails.type)

assertThat(upgradeInfo.oldPurchase.purchaseToken).isEqualTo(oldSkuPurchaseTokenSlot.captured)
assertThat(upgradeInfo.prorationMode).isEqualTo(prorationModeSlot.captured)
billingClientOKResult
}

Expand Down
Expand Up @@ -31,6 +31,7 @@ import com.revenuecat.purchases.common.buildPurchaserInfo
import com.revenuecat.purchases.common.caching.DeviceCache
import com.revenuecat.purchases.common.createOfferings
import com.revenuecat.purchases.common.sha1
import com.revenuecat.purchases.google.sku
import com.revenuecat.purchases.google.toProductDetails
import com.revenuecat.purchases.google.toRevenueCatPurchaseDetails
import com.revenuecat.purchases.google.toSKUType
Expand Down
Expand Up @@ -11,4 +11,8 @@ object BillingStrings {
const val BILLING_UNAVAILABLE = "Billing is not available in this device. %s"
const val BILLING_WRAPPER_PURCHASES_ERROR = "BillingWrapper purchases failed to update: %s"
const val BILLING_WRAPPER_PURCHASES_UPDATED = "BillingWrapper purchases updated: %s"
const val BILLING_PURCHASE_HISTORY_RECORD_MORE_THAN_ONE_SKU = "There's more than one sku in the " +
"PurchaseHistoryRecord, but only one will be used."
const val BILLING_PURCHASE_MORE_THAN_ONE_SKU = "There's more than one sku in the PurchaseHistoryRecord, " +
"but only one will be used."
}

0 comments on commit f6554bb

Please sign in to comment.