diff --git a/app/src/main/java/com/limurse/iapsample/JavaSampleActivity.java b/app/src/main/java/com/limurse/iapsample/JavaSampleActivity.java index b747e0e..88d892e 100644 --- a/app/src/main/java/com/limurse/iapsample/JavaSampleActivity.java +++ b/app/src/main/java/com/limurse/iapsample/JavaSampleActivity.java @@ -102,11 +102,11 @@ public void onPurchaseFailed(@Nullable DataWrappers.PurchaseInfo purchaseInfo, @ ); binding.btnMonthly.setOnClickListener(it -> - iapConnector.subscribe(this, "subscription", null, null) + iapConnector.subscribe(this, "subscription", null, null, null) ); binding.btnYearly.setOnClickListener(it -> - iapConnector.subscribe(this, "yearly", null, null) + iapConnector.subscribe(this, "yearly", null, null, null) ); binding.btnQuite.setOnClickListener(it -> diff --git a/app/src/main/java/com/limurse/iapsample/KotlinSampleActivity.kt b/app/src/main/java/com/limurse/iapsample/KotlinSampleActivity.kt index 77d16c5..b42836b 100644 --- a/app/src/main/java/com/limurse/iapsample/KotlinSampleActivity.kt +++ b/app/src/main/java/com/limurse/iapsample/KotlinSampleActivity.kt @@ -51,7 +51,7 @@ class KotlinSampleActivity : AppCompatActivity() { }) iapConnector.addPurchaseListener(object : PurchaseServiceListener { - override fun onPricesUpdated(iapKeyPrices: Map>) { + override fun onPricesUpdated(iapKeyPrices: Map) { // list of available products will be received here, so you can update UI with prices if needed } @@ -102,7 +102,7 @@ class KotlinSampleActivity : AppCompatActivity() { } } - override fun onPricesUpdated(iapKeyPrices: Map>) { + override fun onPricesUpdated(iapKeyPrices: Map) { // list of available products will be received here, so you can update UI with prices if needed } diff --git a/iap/src/main/java/com/limurse/iap/BillingService.kt b/iap/src/main/java/com/limurse/iap/BillingService.kt index bf64d3c..40c8e68 100644 --- a/iap/src/main/java/com/limurse/iap/BillingService.kt +++ b/iap/src/main/java/com/limurse/iap/BillingService.kt @@ -82,19 +82,19 @@ class BillingService( return } - launchBillingFlow(activity, sku, BillingClient.ProductType.INAPP, obfuscatedAccountId, obfuscatedProfileId) + launchBillingFlow(activity, sku, BillingClient.ProductType.INAPP, null, obfuscatedAccountId, obfuscatedProfileId) } - override fun subscribe(activity: Activity, sku: String, obfuscatedAccountId: String?, obfuscatedProfileId: String?) { + override fun subscribe(activity: Activity, sku: String, offerId: String?, obfuscatedAccountId: String?, obfuscatedProfileId: String?) { if (!sku.isProductReady()) { log("buy. Google billing service is not ready yet. (SKU is not ready yet -2)") return } - launchBillingFlow(activity, sku, BillingClient.ProductType.SUBS, obfuscatedAccountId, obfuscatedProfileId) + launchBillingFlow(activity, sku, BillingClient.ProductType.SUBS, offerId, obfuscatedAccountId, obfuscatedProfileId) } - private fun launchBillingFlow(activity: Activity, sku: String, type: String, obfuscatedAccountId: String?, obfuscatedProfileId: String?) { + private fun launchBillingFlow(activity: Activity, sku: String, type: String, offerId: String?, obfuscatedAccountId: String?, obfuscatedProfileId: String?) { sku.toProductDetails(type) { productDetails -> if (productDetails != null) { @@ -102,8 +102,14 @@ class BillingService( val builder = BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(productDetails) - if(type == BillingClient.ProductType.SUBS){ - productDetails.subscriptionOfferDetails?.getOrNull(0)?.let { + if(type == BillingClient.ProductType.SUBS) { + var index = 0 + productDetails.subscriptionOfferDetails?.indexOfFirst { it.offerId == offerId }?.also { + if (it >= 0) { + index = it + } + } + productDetails.subscriptionOfferDetails?.getOrNull(index)?.also { builder.setOfferToken(it.offerToken) } } @@ -306,30 +312,49 @@ class BillingService( entry.value?.let { when(it.productType){ BillingClient.ProductType.SUBS->{ - entry.key to (it.subscriptionOfferDetails?.getOrNull(0)?.pricingPhases?.pricingPhaseList?.map { pricingPhase -> - DataWrappers.ProductDetails( - title = it.title, - description = it.description, - priceCurrencyCode = pricingPhase.priceCurrencyCode, - price = pricingPhase.formattedPrice, - priceAmount = pricingPhase.priceAmountMicros.div(1000000.0), - billingCycleCount = pricingPhase.billingCycleCount, - billingPeriod = pricingPhase.billingPeriod, - recurrenceMode = pricingPhase.recurrenceMode - ) - } ?: listOf()) + entry.key to DataWrappers.ProductDetails( + title = it.title, + description = it.description, + offers = it.subscriptionOfferDetails?.map { offerDetails -> + DataWrappers.Offer( + id = offerDetails.offerId, + token = offerDetails.offerToken, + tags = offerDetails.offerTags, + pricingPhases = offerDetails.pricingPhases.pricingPhaseList.map { pricingPhase -> + DataWrappers.PricingPhase( + priceCurrencyCode = pricingPhase.priceCurrencyCode, + price = pricingPhase.formattedPrice, + priceAmount = pricingPhase.priceAmountMicros.div(1000000.0), + billingCycleCount = pricingPhase.billingCycleCount, + billingPeriod = pricingPhase.billingPeriod, + recurrenceMode = pricingPhase.recurrenceMode + ) + } + ) + } + ) } else->{ - entry.key to listOf(DataWrappers.ProductDetails( + entry.key to DataWrappers.ProductDetails( title = it.title, description = it.description, - priceCurrencyCode = it.oneTimePurchaseOfferDetails?.priceCurrencyCode, - price = it.oneTimePurchaseOfferDetails?.formattedPrice, - priceAmount = it.oneTimePurchaseOfferDetails?.priceAmountMicros?.div(1000000.0), - billingCycleCount = null, - billingPeriod = null, - recurrenceMode = ProductDetails.RecurrenceMode.NON_RECURRING - )) + offers = it.oneTimePurchaseOfferDetails?.let { offerDetails -> + listOf(DataWrappers.Offer( + id = null, + token = null, + tags = null, + pricingPhases = listOf( + DataWrappers.PricingPhase( + priceCurrencyCode = offerDetails.priceCurrencyCode, + price = offerDetails.formattedPrice, + priceAmount = offerDetails.priceAmountMicros.div(1000000.0), + billingCycleCount = null, + billingPeriod = null, + recurrenceMode = ProductDetails.RecurrenceMode.NON_RECURRING + )) + )) + } ?: listOf() + ) } } } diff --git a/iap/src/main/java/com/limurse/iap/BillingServiceListener.kt b/iap/src/main/java/com/limurse/iap/BillingServiceListener.kt index 2b53399..3836ece 100644 --- a/iap/src/main/java/com/limurse/iap/BillingServiceListener.kt +++ b/iap/src/main/java/com/limurse/iap/BillingServiceListener.kt @@ -6,7 +6,7 @@ interface BillingServiceListener { * * @param iapKeyPrices - a map with available products */ - fun onPricesUpdated(iapKeyPrices: Map>) + fun onPricesUpdated(iapKeyPrices: Map) /** * Callback will be triggered when a purchase was failed. diff --git a/iap/src/main/java/com/limurse/iap/DataWrappers.kt b/iap/src/main/java/com/limurse/iap/DataWrappers.kt index 38b2b9e..42da225 100644 --- a/iap/src/main/java/com/limurse/iap/DataWrappers.kt +++ b/iap/src/main/java/com/limurse/iap/DataWrappers.kt @@ -7,12 +7,7 @@ class DataWrappers { data class ProductDetails( val title: String?, val description: String?, - val price: String?, - val priceAmount: Double?, - val priceCurrencyCode: String?, - val billingCycleCount: Int?, - val billingPeriod: String?, - val recurrenceMode: Int? + val offers: List? ) data class PurchaseInfo( @@ -29,4 +24,20 @@ class DataWrappers { val sku: String, val accountIdentifiers: AccountIdentifiers? ) + + data class Offer( + val id: String?, + val token: String?, + val tags: List?, + val pricingPhases: List + ) + + data class PricingPhase( + val price: String?, + val priceAmount: Double?, + val priceCurrencyCode: String?, + val billingCycleCount: Int?, + val billingPeriod: String?, + val recurrenceMode: Int? + ) } \ No newline at end of file diff --git a/iap/src/main/java/com/limurse/iap/IBillingService.kt b/iap/src/main/java/com/limurse/iap/IBillingService.kt index 4411b10..6476320 100644 --- a/iap/src/main/java/com/limurse/iap/IBillingService.kt +++ b/iap/src/main/java/com/limurse/iap/IBillingService.kt @@ -83,13 +83,13 @@ abstract class IBillingService { } } - fun updatePrices(iapKeyPrices: Map>) { + fun updatePrices(iapKeyPrices: Map) { findUiHandler().post { updatePricesInternal(iapKeyPrices) } } - private fun updatePricesInternal(iapKeyPrices: Map>) { + private fun updatePricesInternal(iapKeyPrices: Map) { for (billingServiceListener in purchaseServiceListeners) { billingServiceListener.onPricesUpdated(iapKeyPrices) } @@ -121,7 +121,7 @@ abstract class IBillingService { abstract fun init(key: String?) abstract fun buy(activity: Activity, sku: String, obfuscatedAccountId: String?, obfuscatedProfileId: String?) - abstract fun subscribe(activity: Activity, sku: String, obfuscatedAccountId: String?, obfuscatedProfileId: String?) + abstract fun subscribe(activity: Activity, sku: String, offerId: String?, obfuscatedAccountId: String?, obfuscatedProfileId: String?) abstract fun unsubscribe(activity: Activity, sku: String) abstract fun enableDebugLogging(enable: Boolean) diff --git a/iap/src/main/java/com/limurse/iap/IapConnector.kt b/iap/src/main/java/com/limurse/iap/IapConnector.kt index eb68c51..057af5c 100644 --- a/iap/src/main/java/com/limurse/iap/IapConnector.kt +++ b/iap/src/main/java/com/limurse/iap/IapConnector.kt @@ -61,8 +61,9 @@ class IapConnector @JvmOverloads constructor( getBillingService().buy(activity, sku, obfuscatedAccountId, obfuscatedProfileId) } - fun subscribe(activity: Activity, sku: String, obfuscatedAccountId: String? = null, obfuscatedProfileId: String? = null) { - getBillingService().subscribe(activity, sku, obfuscatedAccountId, obfuscatedProfileId) + fun subscribe(activity: Activity, sku: String, offerId: String? = null, + obfuscatedAccountId: String? = null, obfuscatedProfileId: String? = null) { + getBillingService().subscribe(activity, sku, offerId, obfuscatedAccountId, obfuscatedProfileId) } fun unsubscribe(activity: Activity, sku: String) { diff --git a/iap/src/main/java/com/limurse/iap/PurchaseServiceListener.kt b/iap/src/main/java/com/limurse/iap/PurchaseServiceListener.kt index 8d36931..36867c2 100644 --- a/iap/src/main/java/com/limurse/iap/PurchaseServiceListener.kt +++ b/iap/src/main/java/com/limurse/iap/PurchaseServiceListener.kt @@ -6,7 +6,7 @@ interface PurchaseServiceListener : BillingServiceListener { * * @param iapKeyPrices - a map with available products */ - override fun onPricesUpdated(iapKeyPrices: Map>) + override fun onPricesUpdated(iapKeyPrices: Map) /** * Callback will be triggered when a product purchased successfully