Skip to content

Commit

Permalink
Merge pull request #2 from hansemannn/feature/android-play-billing-v5
Browse files Browse the repository at this point in the history
feat: support play-billing v5
  • Loading branch information
hansemannn committed Oct 3, 2022
2 parents 2597f0d + f4ca649 commit cda9f5a
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 12 deletions.
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ apply plugin: "kotlin-android-extensions"
dependencies {
implementation "androidx.core:core-ktx:1.3.0"

def inapp_version = "3.0.3"
def inapp_version = "5.0.0"
implementation "com.android.billingclient:billing:${inapp_version}"
implementation "com.android.billingclient:billing-ktx:${inapp_version}"
}
Expand Down
2 changes: 1 addition & 1 deletion android/manifest
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# this is your module manifest and used by Titanium
# during compilation, packaging, distribution, etc.
#
version: 2.3.0
version: 3.0.0
apiversion: 4
architectures: arm64-v8a armeabi-v7a x86 x86_64
description: titanium-in-app-purchase
Expand Down
2 changes: 2 additions & 0 deletions android/src/ti/iap/IAPConstants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ object IAPConstants {
object PurchaseModelKeys {
const val PURCHASE_TOKEN = "purchaseToken"
const val PRODUCT_ID = "productId"
const val PRODUCT_IDS = "productIds" // Added in Play Billing v4+
const val ORDER_ID = "orderId"
const val QUANTITY = "quantity"
const val DEVELOPER_PAYLOAD = "developerPayload"
const val ORIGINAL_JSON = "originalJson"
const val PACKAGE_NAME = "packageName"
Expand Down
56 changes: 48 additions & 8 deletions android/src/ti/iap/TitaniumInAppPurchaseModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import com.android.billingclient.api.BillingClient.FeatureType.*
import com.android.billingclient.api.BillingClient.SkuType.INAPP
import com.android.billingclient.api.BillingClient.SkuType.SUBS
import com.android.billingclient.api.Purchase.PurchaseState.*
import com.android.billingclient.api.PurchasesUpdatedListener
import org.appcelerator.kroll.KrollDict
import org.appcelerator.kroll.KrollFunction
import org.appcelerator.kroll.KrollModule
Expand All @@ -29,6 +28,10 @@ import ti.iap.handlers.ProductsHandler
import ti.iap.handlers.PurchaseHandler
import ti.iap.helper.QueryHandler
import ti.iap.models.PurchaseModel
import java.lang.Error
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

@Kroll.module(name = "TitaniumInAppPurchase", id = "ti.iap")
class TitaniumInAppPurchaseModule : KrollModule() {
Expand All @@ -39,10 +42,10 @@ class TitaniumInAppPurchaseModule : KrollModule() {
companion object {
const val LCAT = "TitaniumIAP"

@Kroll.constant const val FEATURE_TYPE_IN_APP_ITEMS_ON_VR = IN_APP_ITEMS_ON_VR // Purchase/query for in-app items on VR
@Kroll.constant const val FEATURE_TYPE_IN_APP_ITEMS_ON_VR = -1 // Purchase/query for in-app items on VR (removed in v5)
@Kroll.constant const val FEATURE_TYPE_PRICE_CHANGE_CONFIRMATION = PRICE_CHANGE_CONFIRMATION // Launch a price change confirmation flow
@Kroll.constant const val FEATURE_TYPE_SUBSCRIPTIONS = SUBSCRIPTIONS // Purchase/query for subscriptions
@Kroll.constant const val FEATURE_TYPE_SUBSCRIPTIONS_ON_VR = SUBSCRIPTIONS_ON_VR // Purchase/query for subscriptions on VR
@Kroll.constant const val FEATURE_TYPE_SUBSCRIPTIONS_ON_VR = -2 // Purchase/query for subscriptions on VR (removed in v5)
@Kroll.constant const val FEATURE_TYPE_SUBSCRIPTIONS_UPDATE = SUBSCRIPTIONS_UPDATE // Subscriptions update/replace

@Kroll.constant const val SKU_TYPE_INAPP = INAPP
Expand Down Expand Up @@ -88,6 +91,13 @@ class TitaniumInAppPurchaseModule : KrollModule() {
billingClient?.startConnection(billingConnectionState as BillingClientStateListener)
}

@Kroll.method
fun getConnectionState(): Int? {
billingClient?.let {
return it.connectionState
} ?: return null
}

@Kroll.method
fun disconnect() {
billingClient?.endConnection()
Expand All @@ -110,6 +120,8 @@ class TitaniumInAppPurchaseModule : KrollModule() {
val productId = args[IAPConstants.PurchaseModelKeys.PRODUCT_ID] as String
val skuDetails = ProductsHandler.getSkuDetails(productId) ?: return

org.appcelerator.kroll.common.Log.w("Ti.IAP", "The \"launchPriceChangeConfirmationFlow\" method has been deprecated by Google and may be removed in the future.")

val params = PriceChangeFlowParams.newBuilder().setSkuDetails(skuDetails).build()
billingClient?.launchPriceChangeConfirmationFlow(TiApplication.getInstance().rootOrCurrentActivity, params) { billingResult ->
val event = KrollDict()
Expand Down Expand Up @@ -196,6 +208,7 @@ class TitaniumInAppPurchaseModule : KrollModule() {

@Kroll.method
fun queryPurchases(args: KrollDict): KrollDict {
val callback = args["callback"] as KrollFunction
val purchaseList = ArrayList<KrollDict>()
val resultDict = KrollDict()
resultDict[IAPConstants.Properties.SUCCESS] = false
Expand All @@ -206,14 +219,21 @@ class TitaniumInAppPurchaseModule : KrollModule() {
resultDict[IAPConstants.Properties.CODE] = OK

val productType = args.optString(IAPConstants.Properties.PRODUCT_TYPE, SKU_TYPE_INAPP)
val queryPurchaseResult = billingClient!!.queryPurchases(productType)
val params = QueryPurchasesParams.newBuilder().setProductType(productType).build()

if (queryPurchaseResult.responseCode == OK) {
if (queryPurchaseResult.purchasesList != null && queryPurchaseResult.purchasesList!!.isNotEmpty()) {
for (purchase in queryPurchaseResult.purchasesList!!) {
purchaseList.add(PurchaseModel(purchase).modelData)
billingClient?.queryPurchasesAsync(params) { billingResult, purchasesList ->
val event = KrollDict()
if (billingResult.responseCode == OK) {
if (purchasesList.isNotEmpty()) {
for (purchase in purchasesList) {
purchaseList.add(PurchaseModel(purchase).modelData)
}
}
event["purchaseList"] = purchaseList
event["code"] = billingResult.responseCode
event["success"] = billingResult.responseCode == OK
}
callback.callAsync(getKrollObject(), event)
}
}

Expand All @@ -222,6 +242,26 @@ class TitaniumInAppPurchaseModule : KrollModule() {
return resultDict
}

@Kroll.method
fun queryPurchasesAsync(args: KrollDict) {
org.appcelerator.kroll.common.Log.e("Ti.IAP", "The \"queryPurchasesAsync\" API has been removed, use \"queryPurchases\" instead!")
}

@Kroll.method
fun showInAppMessages(callback: KrollFunction) {
val params = InAppMessageParams.newBuilder().build()
billingClient?.showInAppMessages(TiApplication.getAppCurrentActivity(), params) { inAppMessageResult ->
val event = KrollDict()
event["code"] = inAppMessageResult.responseCode
if (inAppMessageResult.responseCode == InAppMessageResult.InAppMessageResponseCode.NO_ACTION_NEEDED) {
// The flow has finished and there is no action needed from developers.
} else if (inAppMessageResult.responseCode == InAppMessageResult.InAppMessageResponseCode.SUBSCRIPTION_STATUS_UPDATED) {
event["purchaseToken"] = inAppMessageResult.purchaseToken
}
callback.callAsync(getKrollObject(), event)
}
}

@Kroll.method
fun queryPurchaseHistoryAsync(args: KrollDict) {
if (isBillingLibraryReady(args)) {
Expand Down
8 changes: 6 additions & 2 deletions android/src/ti/iap/models/PurchaseModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ class PurchaseModel(val purchase: Purchase) {
val modelDict = KrollDict()

modelDict[PurchaseModelKeys.PURCHASE_TOKEN] = purchase.purchaseToken // primary-key and globally unique, can be used in database records safely
modelDict[PurchaseModelKeys.PRODUCT_ID] = purchase.sku
modelDict[PurchaseModelKeys.PRODUCT_ID] = purchase.skus.first()
modelDict[PurchaseModelKeys.PRODUCT_IDS] = purchase.skus
modelDict[PurchaseModelKeys.ORDER_ID] = purchase.orderId
modelDict[PurchaseModelKeys.QUANTITY] = purchase.quantity
modelDict[PurchaseModelKeys.DEVELOPER_PAYLOAD] = purchase.developerPayload
// modelDict[PurchaseModelKeys.ORIGINAL_JSON] = purchase.originalJson
modelDict[PurchaseModelKeys.PACKAGE_NAME] = purchase.packageName
Expand All @@ -31,8 +33,10 @@ class PurchaseModel(val purchase: Purchase) {
val modelDict = KrollDict()

modelDict[PurchaseModelKeys.PURCHASE_TOKEN] = purchaseHistoryRecord.purchaseToken // primary-key and globally unique, can be used in database records safely
modelDict[PurchaseModelKeys.PRODUCT_ID] = purchaseHistoryRecord.sku
modelDict[PurchaseModelKeys.PRODUCT_ID] = purchaseHistoryRecord.skus.first()
modelDict[PurchaseModelKeys.PRODUCT_IDS] = purchaseHistoryRecord.skus
modelDict[PurchaseModelKeys.ORDER_ID] = null
modelDict[PurchaseModelKeys.QUANTITY] = purchaseHistoryRecord.quantity
modelDict[PurchaseModelKeys.DEVELOPER_PAYLOAD] = purchaseHistoryRecord.developerPayload
// modelDict[PurchaseModelKeys.ORIGINAL_JSON] = purchaseHistoryRecord.originalJson
modelDict[PurchaseModelKeys.PACKAGE_NAME] = null
Expand Down

0 comments on commit cda9f5a

Please sign in to comment.