Skip to content

Commit

Permalink
Add supported library versions parameter to event
Browse files Browse the repository at this point in the history
Summary: In this diff, we add the supported library versions parameter to the event.

Reviewed By: jjiang10

Differential Revision: D62419586

fbshipit-source-id: 3ade389c0446d3409b43bef5faf5356af0a5357a
  • Loading branch information
maxalbrightmeta authored and facebook-github-bot committed Sep 29, 2024
1 parent 9be3499 commit a7fe2a5
Show file tree
Hide file tree
Showing 11 changed files with 287 additions and 202 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,132 +26,156 @@ import org.json.JSONException
import org.json.JSONObject

object InAppPurchaseActivityLifecycleTracker {
private val TAG = InAppPurchaseActivityLifecycleTracker::class.java.canonicalName
private const val SERVICE_INTERFACE_NAME =
"com.android.vending.billing.IInAppBillingService\$Stub"
private const val BILLING_ACTIVITY_NAME = "com.android.billingclient.api.ProxyBillingActivity"
private val isTracking = AtomicBoolean(false)
private var hasBillingService: Boolean? = null
private var hasBillingActivity: Boolean? = null
private lateinit var serviceConnection: ServiceConnection
private lateinit var callbacks: Application.ActivityLifecycleCallbacks
private lateinit var intent: Intent
private var inAppBillingObj: Any? = null

/** Start iap logging if enable, initialize billing service if not */
@JvmStatic
fun startIapLogging() {
initializeIfNotInitialized()
if (hasBillingService == false) {
return
}
if (isImplicitPurchaseLoggingEnabled()) {
startTracking()
}
}
private val TAG = InAppPurchaseActivityLifecycleTracker::class.java.canonicalName
private const val SERVICE_INTERFACE_NAME =
"com.android.vending.billing.IInAppBillingService\$Stub"
private const val BILLING_ACTIVITY_NAME = "com.android.billingclient.api.ProxyBillingActivity"
private val isTracking = AtomicBoolean(false)
private var hasBillingService: Boolean? = null
private var hasBillingActivity: Boolean? = null
private lateinit var serviceConnection: ServiceConnection
private lateinit var callbacks: Application.ActivityLifecycleCallbacks
private lateinit var intent: Intent
private var inAppBillingObj: Any? = null
private var billingClientVersion: InAppPurchaseUtils.BillingClientVersion? = null

private fun initializeIfNotInitialized() {
if (hasBillingService != null) {
return
/** Start iap logging if enable, initialize billing service if not */
@JvmStatic
fun startIapLogging(billingClientVersion: InAppPurchaseUtils.BillingClientVersion) {
initializeIfNotInitialized()
if (hasBillingService == false) {
return
}
if (isImplicitPurchaseLoggingEnabled()) {
this.billingClientVersion = billingClientVersion
startTracking()
}
}

hasBillingService = InAppPurchaseUtils.getClass(SERVICE_INTERFACE_NAME) != null
if (hasBillingService == false) {
return
}
private fun initializeIfNotInitialized() {
if (hasBillingService != null) {
return
}

hasBillingService = InAppPurchaseUtils.getClass(SERVICE_INTERFACE_NAME) != null
if (hasBillingService == false) {
return
}

hasBillingActivity = InAppPurchaseUtils.getClass(BILLING_ACTIVITY_NAME) != null
hasBillingActivity = InAppPurchaseUtils.getClass(BILLING_ACTIVITY_NAME) != null

InAppPurchaseEventManager.clearSkuDetailsCache()
InAppPurchaseEventManager.clearSkuDetailsCache()

intent =
Intent("com.android.vending.billing.InAppBillingService.BIND")
.setPackage("com.android.vending")
serviceConnection =
object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
inAppBillingObj =
InAppPurchaseEventManager.asInterface(getApplicationContext(), service)
}
intent =
Intent("com.android.vending.billing.InAppBillingService.BIND")
.setPackage("com.android.vending")
serviceConnection =
object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
inAppBillingObj =
InAppPurchaseEventManager.asInterface(getApplicationContext(), service)
}

override fun onServiceDisconnected(name: ComponentName) = Unit
}
callbacks =
object : Application.ActivityLifecycleCallbacks {
override fun onActivityResumed(activity: Activity) {
try {
getExecutor().execute {
val context = getApplicationContext()
val purchasesInapp =
InAppPurchaseEventManager.getPurchasesInapp(context, inAppBillingObj)
logPurchase(context, purchasesInapp, false)
val purchasesSubs =
InAppPurchaseEventManager.getPurchasesSubs(context, inAppBillingObj)
logPurchase(context, purchasesSubs, true)
}
} catch (ep: Exception) {
/*no op*/
override fun onServiceDisconnected(name: ComponentName) = Unit
}
}
callbacks =
object : Application.ActivityLifecycleCallbacks {
override fun onActivityResumed(activity: Activity) {
try {
getExecutor().execute {
val context = getApplicationContext()
val purchasesInapp =
InAppPurchaseEventManager.getPurchasesInapp(
context,
inAppBillingObj
)
logPurchase(context, purchasesInapp, false)
val purchasesSubs =
InAppPurchaseEventManager.getPurchasesSubs(context, inAppBillingObj)
logPurchase(context, purchasesSubs, true)
}
} catch (ep: Exception) {
/*no op*/
}
}

override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = Unit
override fun onActivityStarted(activity: Activity) = Unit
override fun onActivityPaused(activity: Activity) = Unit
override fun onActivityStopped(activity: Activity) {
try {
if (hasBillingActivity == true && activity.localClassName == BILLING_ACTIVITY_NAME) {
getExecutor().execute {
val context = getApplicationContext()
var purchases =
InAppPurchaseEventManager.getPurchasesInapp(context, inAppBillingObj)
if (purchases.isEmpty()) {
purchases =
InAppPurchaseEventManager.getPurchaseHistoryInapp(context, inAppBillingObj)
}
logPurchase(context, purchases, false)
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) =
Unit

override fun onActivityStarted(activity: Activity) = Unit
override fun onActivityPaused(activity: Activity) = Unit
override fun onActivityStopped(activity: Activity) {
try {
if (hasBillingActivity == true && activity.localClassName == BILLING_ACTIVITY_NAME) {
getExecutor().execute {
val context = getApplicationContext()
var purchases =
InAppPurchaseEventManager.getPurchasesInapp(
context,
inAppBillingObj
)
if (purchases.isEmpty()) {
purchases =
InAppPurchaseEventManager.getPurchaseHistoryInapp(
context,
inAppBillingObj
)
}
logPurchase(context, purchases, false)
}
}
} catch (ep: Exception) {
/*no op*/
}
}
}
} catch (ep: Exception) {
/*no op*/
}
}

override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
override fun onActivityDestroyed(activity: Activity) = Unit
}
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) =
Unit

private fun startTracking() {
if (!isTracking.compareAndSet(false, true)) {
return
}
val context = getApplicationContext()
if (context is Application) {
context.registerActivityLifecycleCallbacks(callbacks)
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
override fun onActivityDestroyed(activity: Activity) = Unit
}
}
}

private fun logPurchase(context: Context, purchases: ArrayList<String>, isSubscription: Boolean) {
if (purchases.isEmpty()) {
return
}
val purchaseMap = hashMapOf<String, String>()
val skuList = arrayListOf<String>()
for (purchase in purchases) {
try {
val purchaseJson = JSONObject(purchase)
val sku = purchaseJson.getString("productId")
purchaseMap[sku] = purchase
skuList.add(sku)
} catch (e: JSONException) {
Log.e(TAG, "Error parsing in-app purchase data.", e)
}
private fun startTracking() {
if (!isTracking.compareAndSet(false, true)) {
return
}
val context = getApplicationContext()
if (context is Application) {
context.registerActivityLifecycleCallbacks(callbacks)
context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
}
}
val skuDetailsMap =
InAppPurchaseEventManager.getSkuDetails(context, skuList, inAppBillingObj, isSubscription)
for ((key, value) in skuDetailsMap) {
purchaseMap[key]?.let { logPurchase(it, value, isSubscription) }

private fun logPurchase(
context: Context,
purchases: ArrayList<String>,
isSubscription: Boolean
) {
if (purchases.isEmpty()) {
return
}
val purchaseMap = hashMapOf<String, String>()
val skuList = arrayListOf<String>()
for (purchase in purchases) {
try {
val purchaseJson = JSONObject(purchase)
val sku = purchaseJson.getString("productId")
purchaseMap[sku] = purchase
skuList.add(sku)
} catch (e: JSONException) {
Log.e(TAG, "Error parsing in-app purchase data.", e)
}
}
val skuDetailsMap =
InAppPurchaseEventManager.getSkuDetails(
context,
skuList,
inAppBillingObj,
isSubscription
)
for ((key, value) in skuDetailsMap) {
purchaseMap[key]?.let { logPurchase(it, value, isSubscription, billingClientVersion) }
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
package com.facebook.appevents.iap

import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.V2_V4
import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.V5_Plus
import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.V5_V7
import com.facebook.appevents.iap.InAppPurchaseUtils.IAPProductType.INAPP
import android.content.Context
import androidx.annotation.RestrictTo
Expand All @@ -35,7 +35,7 @@ object InAppPurchaseAutoLogger {
if (billingClientVersion == V2_V4) {
billingClientWrapper =
InAppPurchaseBillingClientWrapperV2V4.getOrCreateInstance(context)
} else if (billingClientVersion == V5_Plus) {
} else if (billingClientVersion == V5_V7) {
billingClientWrapper =
InAppPurchaseBillingClientWrapperV5V7.getOrCreateInstance(context)
}
Expand All @@ -59,13 +59,15 @@ object InAppPurchaseAutoLogger {
InAppPurchaseBillingClientWrapperV2V4.iapPurchaseDetailsMap,
InAppPurchaseBillingClientWrapperV2V4.skuDetailsMap,
false,
packageName
packageName,
billingClientVersion
)
InAppPurchaseLoggerManager.filterPurchaseLogging(
InAppPurchaseBillingClientWrapperV2V4.subsPurchaseDetailsMap,
InAppPurchaseBillingClientWrapperV2V4.skuDetailsMap,
true,
packageName
packageName,
billingClientVersion
)
InAppPurchaseBillingClientWrapperV2V4.iapPurchaseDetailsMap.clear()
InAppPurchaseBillingClientWrapperV2V4.subsPurchaseDetailsMap.clear()
Expand All @@ -74,13 +76,15 @@ object InAppPurchaseAutoLogger {
InAppPurchaseBillingClientWrapperV5V7.iapPurchaseDetailsMap,
InAppPurchaseBillingClientWrapperV5V7.productDetailsMap,
false,
packageName
packageName,
billingClientVersion
)
InAppPurchaseLoggerManager.filterPurchaseLogging(
InAppPurchaseBillingClientWrapperV5V7.subsPurchaseDetailsMap,
InAppPurchaseBillingClientWrapperV5V7.productDetailsMap,
true,
packageName
packageName,
billingClientVersion
)
InAppPurchaseBillingClientWrapperV5V7.iapPurchaseDetailsMap.clear()
InAppPurchaseBillingClientWrapperV5V7.subsPurchaseDetailsMap.clear()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ object InAppPurchaseLoggerManager {
purchaseDetailsMap: MutableMap<String, JSONObject>,
skuDetailsMap: Map<String, JSONObject?>,
isSubscription: Boolean,
packageName: String
packageName: String,
billingClientVersion: InAppPurchaseUtils.BillingClientVersion

) {
readPurchaseCache()
Expand All @@ -79,12 +80,16 @@ object InAppPurchaseLoggerManager {
skuDetailsMap,
packageName
)
logPurchases(loggingReadyMap, isSubscription)
logPurchases(loggingReadyMap, isSubscription, billingClientVersion)
}

private fun logPurchases(purchaseDetailsMap: Map<String, String>, isSubscription: Boolean) {
private fun logPurchases(
purchaseDetailsMap: Map<String, String>,
isSubscription: Boolean,
billingClientVersion: InAppPurchaseUtils.BillingClientVersion
) {
for ((purchaseDetails, skuDetails) in purchaseDetailsMap) {
logPurchase(purchaseDetails, skuDetails, isSubscription)
logPurchase(purchaseDetails, skuDetails, isSubscription, billingClientVersion)
}
}

Expand Down
Loading

0 comments on commit a7fe2a5

Please sign in to comment.