Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple offers #190

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class KotlinSampleActivity : AppCompatActivity() {
})

iapConnector.addPurchaseListener(object : PurchaseServiceListener {
override fun onPricesUpdated(iapKeyPrices: Map<String, List<DataWrappers.ProductDetails>>) {
override fun onPricesUpdated(iapKeyPrices: Map<String, DataWrappers.ProductDetails>) {
// list of available products will be received here, so you can update UI with prices if needed
}

Expand Down Expand Up @@ -102,7 +102,7 @@ class KotlinSampleActivity : AppCompatActivity() {
}
}

override fun onPricesUpdated(iapKeyPrices: Map<String, List<DataWrappers.ProductDetails>>) {
override fun onPricesUpdated(iapKeyPrices: Map<String, DataWrappers.ProductDetails>) {
// list of available products will be received here, so you can update UI with prices if needed
}

Expand Down
77 changes: 51 additions & 26 deletions iap/src/main/java/com/limurse/iap/BillingService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -82,28 +82,34 @@ 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) {

val productDetailsParamsList = mutableListOf<BillingFlowParams.ProductDetailsParams>()
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)
}
}
Expand Down Expand Up @@ -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()
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ interface BillingServiceListener {
*
* @param iapKeyPrices - a map with available products
*/
fun onPricesUpdated(iapKeyPrices: Map<String, List<DataWrappers.ProductDetails>>)
fun onPricesUpdated(iapKeyPrices: Map<String, DataWrappers.ProductDetails>)

/**
* Callback will be triggered when a purchase was failed.
Expand Down
23 changes: 17 additions & 6 deletions iap/src/main/java/com/limurse/iap/DataWrappers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<Offer>?
)

data class PurchaseInfo(
Expand All @@ -29,4 +24,20 @@ class DataWrappers {
val sku: String,
val accountIdentifiers: AccountIdentifiers?
)

data class Offer(
val id: String?,
val token: String?,
val tags: List<String>?,
val pricingPhases: List<PricingPhase>
)

data class PricingPhase(
val price: String?,
val priceAmount: Double?,
val priceCurrencyCode: String?,
val billingCycleCount: Int?,
val billingPeriod: String?,
val recurrenceMode: Int?
)
}
6 changes: 3 additions & 3 deletions iap/src/main/java/com/limurse/iap/IBillingService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ abstract class IBillingService {
}
}

fun updatePrices(iapKeyPrices: Map<String, List<DataWrappers.ProductDetails>>) {
fun updatePrices(iapKeyPrices: Map<String, DataWrappers.ProductDetails>) {
findUiHandler().post {
updatePricesInternal(iapKeyPrices)
}
}

private fun updatePricesInternal(iapKeyPrices: Map<String, List<DataWrappers.ProductDetails>>) {
private fun updatePricesInternal(iapKeyPrices: Map<String, DataWrappers.ProductDetails>) {
for (billingServiceListener in purchaseServiceListeners) {
billingServiceListener.onPricesUpdated(iapKeyPrices)
}
Expand Down Expand Up @@ -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)

Expand Down
5 changes: 3 additions & 2 deletions iap/src/main/java/com/limurse/iap/IapConnector.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ interface PurchaseServiceListener : BillingServiceListener {
*
* @param iapKeyPrices - a map with available products
*/
override fun onPricesUpdated(iapKeyPrices: Map<String, List<DataWrappers.ProductDetails>>)
override fun onPricesUpdated(iapKeyPrices: Map<String, DataWrappers.ProductDetails>)

/**
* Callback will be triggered when a product purchased successfully
Expand Down
Loading