diff --git a/android/build.gradle b/android/build.gradle index 16ffe6cf..1dd60892 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -44,8 +44,8 @@ android { } dependencies { - implementation 'com.android.billingclient:billing-ktx:4.1.0' + implementation 'com.android.billingclient:billing:5.0.0' implementation files('jars/in-app-purchasing-2.0.76.jar') - implementation 'androidx.annotation:annotation:1.3.0' + implementation 'androidx.annotation:annotation:1.4.0' } diff --git a/android/src/main/kotlin/com/dooboolab/flutterinapppurchase/AndroidInappPurchasePlugin.kt b/android/src/main/kotlin/com/dooboolab/flutterinapppurchase/AndroidInappPurchasePlugin.kt index 1fdb7293..7e16210d 100644 --- a/android/src/main/kotlin/com/dooboolab/flutterinapppurchase/AndroidInappPurchasePlugin.kt +++ b/android/src/main/kotlin/com/dooboolab/flutterinapppurchase/AndroidInappPurchasePlugin.kt @@ -206,7 +206,8 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler, ) { try { val array = ArrayList() - billingClient!!.queryPurchasesAsync(BillingClient.SkuType.INAPP) + val params = QueryPurchasesParams.newBuilder().apply { setProductType(BillingClient.ProductType.INAPP) }.build() + billingClient!!.queryPurchasesAsync(params) { billingResult, skuDetailsList -> if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) { if (skuDetailsList.size == 0) { @@ -252,9 +253,10 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler, call: MethodCall, safeChannel: MethodResultWrapper ) { - val type = if(call.argument("type") == "subs") BillingClient.SkuType.SUBS else BillingClient.SkuType.INAPP + val type = if(call.argument("type") == "subs") BillingClient.ProductType.SUBS else BillingClient.ProductType.INAPP + val params = QueryPurchasesParams.newBuilder().apply { setProductType(type) }.build() val items = JSONArray() - billingClient!!.queryPurchasesAsync(type) { billingResult, skuDetailsList -> + billingClient!!.queryPurchasesAsync(params) { billingResult, skuDetailsList -> if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) { for (purchase in skuDetailsList) { val item = JSONObject() @@ -355,10 +357,11 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler, call: MethodCall, safeChannel: MethodResultWrapper ) { - val type = if(call.argument("type") == "subs") BillingClient.SkuType.SUBS else BillingClient.SkuType.INAPP + val type = if(call.argument("type") == "subs") BillingClient.ProductType.SUBS else BillingClient.ProductType.INAPP + val params = QueryPurchaseHistoryParams.newBuilder().apply { setProductType(type) }.build() billingClient!!.queryPurchaseHistoryAsync( - type, + params, PurchaseHistoryResponseListener { billingResult, purchaseHistoryRecordList -> if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) { val errorData = BillingError.getErrorFromResponseData(billingResult.responseCode) @@ -391,21 +394,21 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler, call: MethodCall, safeChannel: MethodResultWrapper ) { - val skuArr = call.argument>("skus")!! - val skuList = ArrayList() + val skuArr : ArrayList = call.argument>("skus")!! + val skuList = ArrayList() for (i in skuArr.indices) { - skuList.add(skuArr[i]) + skuList.add(QueryProductDetailsParams.Product.newBuilder().setProductId(skuArr[i]).setProductType(skuType).build()) } - billingClient!!.querySkuDetailsAsync( - SkuDetailsParams.newBuilder().setSkusList(skuList).setType(skuType).build() + billingClient!!.queryProductDetailsAsync( + QueryProductDetailsParams.newBuilder().setProductList(skuList).build() ) { billingResult, skuDetailsList -> if (billingResult.responseCode != BillingClient.BillingResponseCode.OK) { val errorData = BillingError.getErrorFromResponseData(billingResult.responseCode) safeChannel.error(call.method, errorData.code, errorData.message) - return@querySkuDetailsAsync + return@queryProductDetailsAsync } - for (sku in skuDetailsList!!) { + for (sku in skuDetailsList) { if (!skus.contains(sku)) { skus.add(sku) } @@ -414,32 +417,40 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler, val items = JSONArray() for (skuDetails in skuDetailsList) { val item = JSONObject() - item.put("productId", skuDetails.sku) - item.put("price", (skuDetails.priceAmountMicros / 1000000f).toString()) - item.put("currency", skuDetails.priceCurrencyCode) - item.put("type", skuDetails.type) - item.put("localizedPrice", skuDetails.price) + item.put("productId", skuDetails.productId) + item.put("price", ((skuDetails.oneTimePurchaseOfferDetails?.priceAmountMicros ?: 0) / 1000000f).toString()) + item.put("currency", skuDetails.oneTimePurchaseOfferDetails?.priceCurrencyCode) + item.put("type", skuDetails.productType) + item.put("localizedPrice", skuDetails.oneTimePurchaseOfferDetails?.formattedPrice) item.put("title", skuDetails.title) item.put("description", skuDetails.description) - item.put("introductoryPrice", skuDetails.introductoryPrice) - item.put("subscriptionPeriodAndroid", skuDetails.subscriptionPeriod) - item.put("freeTrialPeriodAndroid", skuDetails.freeTrialPeriod) - item.put("introductoryPriceCyclesAndroid", skuDetails.introductoryPriceCycles) - item.put("introductoryPricePeriodAndroid", skuDetails.introductoryPricePeriod) - // new - item.put("iconUrl", skuDetails.iconUrl) - item.put("originalJson", skuDetails.originalJson) - item.put("originalPrice", (skuDetails.priceAmountMicros / 1000000f).toDouble()) + val subs = JSONArray() + if(skuDetails.subscriptionOfferDetails!=null) { + for (it in skuDetails.subscriptionOfferDetails!!) { + for (pricing in it.pricingPhases.pricingPhaseList) { + val subItem = JSONObject() + subItem.put("introductoryPrice", pricing.formattedPrice) + subItem.put("subscriptionPeriodAndroid", pricing.billingPeriod) +// item.put("freeTrialPeriodAndroid", pricing.getRecurrenceMode()) + subItem.put("introductoryPriceCyclesAndroid", pricing.billingCycleCount) +// item.put("introductoryPricePeriodAndroid", pricing.p) + subs.put(subItem) + } + + } + } + item.put("subscriptionOfferDetails", subs) + item.put("originalPrice", ((skuDetails.oneTimePurchaseOfferDetails?.priceAmountMicros ?: 0) / 1000000f).toDouble()) items.put(item) } safeChannel.success(items.toString()) - return@querySkuDetailsAsync + return@queryProductDetailsAsync } catch (je: JSONException) { je.printStackTrace() safeChannel.error(TAG, BillingError.E_BILLING_RESPONSE_JSON_PARSE_ERROR, je.message) } catch (fe: FlutterException) { safeChannel.error(call.method, fe.message, fe.localizedMessage) - return@querySkuDetailsAsync + return@queryProductDetailsAsync } } } @@ -448,16 +459,16 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler, call: MethodCall, safeChannel: MethodResultWrapper ) { - val type = if(call.argument("type") == "subs") BillingClient.SkuType.SUBS else BillingClient.SkuType.INAPP + val type = if(call.argument("type") == "subs") BillingClient.ProductType.SUBS else BillingClient.ProductType.INAPP val obfuscatedAccountId = call.argument("obfuscatedAccountId") val obfuscatedProfileId = call.argument("obfuscatedProfileId") val sku = call.argument("sku") val prorationMode = call.argument("prorationMode")!! val purchaseToken = call.argument("purchaseToken") val builder = newBuilder() - var selectedSku: SkuDetails? = null + var selectedSku: ProductDetails? = null for (skuDetail in skus) { - if (skuDetail.sku == sku) { + if (skuDetail.productId == sku) { selectedSku = skuDetail break } @@ -468,11 +479,14 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler, safeChannel.error(TAG, "buyItemByType", debugMessage) return } - builder.setSkuDetails(selectedSku) + + var arr = ArrayList() + arr.add(ProductDetailsParams.newBuilder().apply { setProductDetails(selectedSku) }.build()) + builder.setProductDetailsParamsList(arr) val params = SubscriptionUpdateParams.newBuilder() if (purchaseToken != null) { - params.setOldSkuPurchaseToken(purchaseToken) + params.setOldPurchaseToken(purchaseToken) } if (obfuscatedAccountId != null) { builder.setObfuscatedAccountId(obfuscatedAccountId) @@ -484,8 +498,8 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler, when (prorationMode) { -1 -> {} //ignore ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE -> { - params.setReplaceSkusProrationMode(ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE) - if (type != BillingClient.SkuType.SUBS) { + params.setReplaceProrationMode(ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE) + if (type != BillingClient.ProductType.SUBS) { safeChannel.error( TAG, "buyItemByType", @@ -498,8 +512,8 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler, ProrationMode.DEFERRED, ProrationMode.IMMEDIATE_WITH_TIME_PRORATION, ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE -> - params.setReplaceSkusProrationMode(prorationMode) - else -> params.setReplaceSkusProrationMode(ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY) + params.setReplaceProrationMode(prorationMode) + else -> params.setReplaceProrationMode(ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY) } if (purchaseToken != null) { @@ -574,6 +588,6 @@ class AndroidInappPurchasePlugin internal constructor() : MethodCallHandler, companion object { private const val TAG = "InappPurchasePlugin" private const val PLAY_STORE_URL = "https://play.google.com/store/account/subscriptions" - private var skus: ArrayList = arrayListOf() + private var skus: ArrayList = arrayListOf() } } \ No newline at end of file