Skip to content

Commit

Permalink
Merge pull request #80 from cb-haripriyan/billing-library-5
Browse files Browse the repository at this point in the history
Billing Library 5 changes
  • Loading branch information
cb-haripriyan authored Dec 5, 2023
2 parents 62d1b54 + a0844e8 commit 022f694
Show file tree
Hide file tree
Showing 16 changed files with 229 additions and 180 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.0.0-beta.1
* Handles Android Billing library 5 changes to handle base plan and offer tokens

## 0.4.0
Chore
* Updates Android Billing library version from 4.x to 5.2.1
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Flutter SDK

> [!NOTE]
> #### Updates for Billing Library 5
> - SDK Version 1.0: This version uses Google Billing Library 5.2.1 APIs to fetch product information from the Google Play Console and make purchases. If you’re integrating Chargebee’s SDK for the first time, then use this version, and if you’re migrating from the older version of SDK to this version, follow the migration steps in this [document](https://www.chargebee.com/docs/2.0/mobile-playstore-billing-library-5.html).
> - SDK Version 0.4.0: This [version](https://github.com/chargebee/chargebee-flutter/tree/main) includes Billing Library 5.2.1 but still uses Billing Library 4.0 APIs to fetch product information from the Google Play Console and make purchases. This will enable you to list or update your Android app on the store without any warnings from Google and give you enough time to migrate to version 2.0.
Chargebee's Flutter SDK enables you to build a seamless and efficient customer experience for your subscription business.

Post-installation, initialization, and authentication with the Chargebee site, this SDK will support the following process.
Expand Down Expand Up @@ -27,7 +32,7 @@ To use Chargebee SDK in your Flutter app, follow these steps:

``` dart
dependencies:
chargebee_flutter: ^0.4.0
chargebee_flutter: ^1.0.0-beta.1
```
2. Install dependency.
Expand Down Expand Up @@ -100,7 +105,7 @@ Pass the `Product` and `CBCustomer` objects to the following function when the
``` dart
try {
final customer = CBCustomer('customerId','firstName','lastName','emailId');
final result = await Chargebee.purchaseStoreProduct(product, customer: customer);
final result = await Chargebee.purchaseProduct(product, customer: customer);
print("subscription id : ${result.subscriptionId}");
print("subscription status : ${result.status}");
} on PlatformException catch (e) {
Expand Down
4 changes: 2 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
group 'com.chargebee.flutter.sdk'
version '0.4.0'
version '1.0.0-beta.1'

buildscript {
ext.kotlin_version = '1.6.0'
Expand Down Expand Up @@ -47,7 +47,7 @@ android {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.chargebee:chargebee-android:1.2.0'
implementation 'com.chargebee:chargebee-android:2.0.0-beta-1'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.android.billingclient:billing-ktx:5.2.1'
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.chargebee.flutter.sdk

import android.app.Activity
import android.content.Context
import android.util.Log
import androidx.annotation.NonNull
import com.chargebee.android.Chargebee
Expand All @@ -25,16 +24,7 @@ import java.util.*

class ChargebeeFlutterSdkPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
private lateinit var channel: MethodChannel
var mItemsList = ArrayList<String>()
var mPlansList = ArrayList<String>()
var mSkuProductList = ArrayList<String>()
var result: MethodChannel.Result? = null
var mContext: Context? = null
var subscriptionStatus = HashMap<String, Any>()
var subscriptionsList = ArrayList<String>()
private lateinit var context: Context
private lateinit var activity: Activity
var queryParam = arrayOf<String>()

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "chargebee_flutter")
Expand Down Expand Up @@ -147,12 +137,11 @@ class ChargebeeFlutterSdkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwar
productIdList,
object : CBCallback.ListProductsCallback<ArrayList<CBProduct>> {
override fun onSuccess(productDetails: ArrayList<CBProduct>) {
mSkuProductList.clear()
var productsList = ArrayList<String>()
for (product in productDetails) {
val jsonMapString = Gson().toJson(product.toMap())
mSkuProductList.add(jsonMapString)
productsList.addAll(product.toProducts())
}
result.success(mSkuProductList)
result.success(productsList)
}

override fun onError(error: CBException) {
Expand Down Expand Up @@ -189,6 +178,7 @@ class ChargebeeFlutterSdkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwar
)
val arrayList: ArrayList<String> = ArrayList<String>()
arrayList.add(args["product"] as String)
val offerToken = args["offerToken"] as String
CBPurchase.retrieveProducts(
activity,
arrayList,
Expand All @@ -201,8 +191,10 @@ class ChargebeeFlutterSdkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwar
)
return
}
val purchaseProductParams =
PurchaseProductParams(productIDs.first(), offerToken)
CBPurchase.purchaseProduct(
productIDs.first(),
purchaseProductParams,
customer,
object : CBCallback.PurchaseCallback<String> {
override fun onSuccess(
Expand Down Expand Up @@ -287,6 +279,7 @@ class ChargebeeFlutterSdkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwar
private fun onResultMap(
id: String, planId: String, customerId: String, status: String
): String {
var subscriptionStatus = HashMap<String, Any>()
subscriptionStatus["subscriptionId"] = id
subscriptionStatus["planId"] = planId
subscriptionStatus["customerId"] = customerId
Expand All @@ -312,6 +305,7 @@ class ChargebeeFlutterSdkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwar
}

private fun retrieveAllItems(queryParams: Map<String, String>? = mapOf(), result: Result) {
var queryParam = arrayOf<String>()
if (queryParams != null)
queryParam = arrayOf(
queryParams["limit"] ?: "",
Expand All @@ -333,6 +327,7 @@ class ChargebeeFlutterSdkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwar
}

private fun retrieveAllPlans(queryParams: Map<String, String>? = mapOf(), result: Result) {
var queryParam = arrayOf<String>()
if (queryParams != null)
queryParam = arrayOf(
queryParams["limit"] ?: "",
Expand All @@ -357,9 +352,10 @@ class ChargebeeFlutterSdkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwar
queryParams: Map<String, String>? = mapOf(),
result: Result
) {
var queryParam = arrayOf<String>()
if (queryParams != null)
queryParam = arrayOf(queryParams["limit"] ?: "")
CBPurchase.retrieveProductIdentifers(queryParam) {
CBPurchase.retrieveProductIdentifiers(queryParam) {
when (it) {
is CBProductIDResult.ProductIds -> {
if (it.IDs.isNotEmpty()) {
Expand Down Expand Up @@ -532,40 +528,72 @@ class ChargebeeFlutterSdkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwar
}
}

fun CBProduct.toMap(): Map<String, Any> {
private fun CBProduct.toProducts(): List<String> {
var products = mutableListOf<String>()
subscriptionOffers?.forEach{
products.add(Gson().toJson(it.toMap(this)))
}
oneTimePurchaseOffer?.let { products.add(Gson().toJson(it.toMap(this))) }
return products
}

private fun PricingPhase.toMap(product: CBProduct): Map<String, Any> {
return mapOf(
"productId" to productId,
"productId" to product.id,
"productTitle" to product.title,
"productPrice" to convertPriceAmountInMicros(),
"productPriceString" to productPrice,
"productTitle" to productTitle,
"currencyCode" to skuDetails.priceCurrencyCode,
"subscriptionPeriod" to subscriptionPeriod()
"productPriceString" to formattedPrice,
"currencyCode" to currencyCode,
"subscriptionPeriod" to defaultSubscriptionPeriod()
)
}

fun CBProduct.convertPriceAmountInMicros(): Double {
return skuDetails.priceAmountMicros / 1_000_000.0
fun defaultSubscriptionPeriod(): Map<String, Any> {
return mapOf(
"periodUnit" to "",
"numberOfUnits" to 0
)
}

fun CBProduct.subscriptionPeriod(): Map<String, Any> {
val subscriptionPeriodMap = if (skuDetails.type == ProductType.SUBS.value) {
val subscriptionPeriod = skuDetails.subscriptionPeriod
val numberOfUnits = subscriptionPeriod.substring(1, subscriptionPeriod.length - 1).toInt()
mapOf(
"periodUnit" to periodUnit(),
"numberOfUnits" to numberOfUnits
)
} else {
mapOf(
"periodUnit" to "",
"numberOfUnits" to 0
)
fun SubscriptionOffer.toMap(product: CBProduct): Map<String, Any> {
val pricingPhase = pricingPhases.last()
val subscription = mutableMapOf(
"productId" to product.id,
"productType" to product.type.value,
"baseProductId" to basePlanId,
"offerToken" to offerToken,
"productTitle" to product.title,
"productPrice" to pricingPhase.convertPriceAmountInMicros(),
"productPriceString" to pricingPhase.formattedPrice,
"currencyCode" to pricingPhase.currencyCode,
"subscriptionPeriod" to pricingPhase.subscriptionPeriod()
)
offerId?.let {
subscription["offer"] = offer()
}
return subscriptionPeriodMap
return subscription
}

fun CBProduct.periodUnit(): String {
return when (skuDetails.subscriptionPeriod.last().toString()) {
private fun SubscriptionOffer.offer(): Map<String, Any> {
val pricingPhase = pricingPhases.first()
return mapOf(
"id" to offerId.orEmpty(),
"price" to pricingPhase.convertPriceAmountInMicros(),
"priceString" to pricingPhase.formattedPrice,
"period" to pricingPhase.subscriptionPeriod()
)
}
private fun PricingPhase.subscriptionPeriod(): Map<String, Any> {
val subscriptionPeriod = billingPeriod
val numberOfUnits = subscriptionPeriod?.substring(1, subscriptionPeriod.length - 1)?.toInt() ?: 0
return mapOf(
"periodUnit" to periodUnit(),
"numberOfUnits" to numberOfUnits
)
}

fun PricingPhase.periodUnit(): String {
return when (this.billingPeriod?.last().toString()) {
"Y" -> "year"
"M" -> "month"
"W" -> "week"
Expand All @@ -590,3 +618,7 @@ internal fun NonSubscription.toMap(): String {
)
return Gson().toJson(resultMap)
}

fun PricingPhase.convertPriceAmountInMicros(): Double {
return amountInMicros / 1_000_000.0
}
4 changes: 2 additions & 2 deletions example/integration_test/chargebee_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class ChargebeeTest {
}

try {
final result = await Chargebee.purchaseProduct(product, 'abc');
final result = await Chargebee.purchaseProduct(product, customer: customer);
debugPrint('purchase result: $result');
expect(result.status, 'true');
tester.printToConsole('Product subscribed successfully!');
Expand Down Expand Up @@ -165,7 +165,7 @@ class ChargebeeTest {
_getProduct(productIdForAndroid);
}
try {
final result = await Chargebee.purchaseStoreProduct(product, customer: customer);
final result = await Chargebee.purchaseProduct(product, customer: customer);
debugPrint('purchase result: $result');
expect(result.status, 'true');
tester.printToConsole('Product subscribed successfully!');
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
<string>11.0</string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion example/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# platform :ios, '11.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
Expand Down
Loading

0 comments on commit 022f694

Please sign in to comment.