Skip to content

Commit

Permalink
Automatically query product details with results of querypurchases/qu…
Browse files Browse the repository at this point in the history
…erypurchasehistory

Summary: In order to query product details, we need to pass in a list of product Ids ([docs](https://developer.android.com/reference/com/android/billingclient/api/QueryProductDetailsParams.Builder)). In order to know what those productIds are, we need to have first queried for purchases or purchase history. Therefore, we need to make the call to queryProductDetailsAsync in the listener of queryPurchasesAsync and queryPurchaseHistoryAsync.

Reviewed By: jjiang10

Differential Revision: D60979363

fbshipit-source-id: 13d73a04dfc937658a1f7b60123f182e1421e13f
  • Loading branch information
maxalbrightmeta authored and facebook-github-bot committed Aug 30, 2024
1 parent 7e7b568 commit 8575b3b
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ private constructor(
val listenerObj = Proxy.newProxyInstance(
purchasesResponseListenerClazz.classLoader,
arrayOf(purchasesResponseListenerClazz),
ListenerWrapper(null)
ListenerWrapper(arrayOf(productType))
)
invokeMethod(
billingClientClazz,
Expand All @@ -288,7 +288,7 @@ private constructor(
val listenerObj = Proxy.newProxyInstance(
purchaseHistoryResponseListenerClazz.classLoader,
arrayOf(purchaseHistoryResponseListenerClazz),
ListenerWrapper(null)
ListenerWrapper(arrayOf(productType))
)
invokeMethod(
billingClientClazz,
Expand All @@ -301,7 +301,7 @@ private constructor(
executeServiceRequest(runnableQuery)
}

fun queryProductDetailsAsync(
private fun queryProductDetailsAsync(
productType: InAppPurchaseUtils.IAPProductType,
productIds: List<String>
) {
Expand Down Expand Up @@ -355,10 +355,15 @@ private constructor(

@AutoHandleExceptions
private fun onQueryPurchasesResponse(wrapperArgs: Array<Any>?, listenerArgs: Array<Any>?) {
val productType = wrapperArgs?.get(0)
if (productType == null || productType !is InAppPurchaseUtils.IAPProductType) {
return
}
val purchaseList = listenerArgs?.get(1)
if (purchaseList == null || purchaseList !is List<*>) {
return
}
val productIds = mutableListOf<String>()
for (purchase in purchaseList) {
val purchaseJsonStr =
invokeMethod(
Expand All @@ -369,17 +374,28 @@ private constructor(
val purchaseJson = JSONObject(purchaseJsonStr)
if (purchaseJson.has(PRODUCT_ID)) {
val productId = purchaseJson.getString(PRODUCT_ID)
if (productId !in productDetailsMap) {
productIds.add(productId)
}
purchaseDetailsMap[productId] = purchaseJson
}
}
if (productIds.isNotEmpty()) {
queryProductDetailsAsync(productType, productIds)
}
}

@AutoHandleExceptions
private fun onPurchaseHistoryResponse(wrapperArgs: Array<Any>?, listenerArgs: Array<Any>?) {
val productType = wrapperArgs?.get(0)
if (productType == null || productType !is InAppPurchaseUtils.IAPProductType) {
return
}
val purchaseHistoryRecordList = listenerArgs?.get(1)
if (purchaseHistoryRecordList == null || purchaseHistoryRecordList !is List<*>) {
return
}
val productIds = mutableListOf<String>()
for (purchaseHistoryRecord in purchaseHistoryRecordList) {
try {
val purchaseHistoryRecordJsonStr = invokeMethod(
Expand All @@ -392,17 +408,24 @@ private constructor(
purchaseHistoryRecordJson.put(PACKAGE_NAME, packageName)
if (purchaseHistoryRecordJson.has(PRODUCT_ID)) {
val productId = purchaseHistoryRecordJson.getString(PRODUCT_ID)
if (productId !in productDetailsMap) {
productIds.add(productId)
}
purchaseDetailsMap[productId] = purchaseHistoryRecordJson
}
} catch (e: Exception) {
/* swallow */
}
}
if (productIds.isNotEmpty()) {
queryProductDetailsAsync(productType, productIds)
}
}

@AutoHandleExceptions
private fun onProductDetailsResponse(wrapperArgs: Array<Any>?, listenerArgs: Array<Any>?) {
val productDetailsList = listenerArgs?.get(1)

if (productDetailsList == null || productDetailsList !is List<*>) {
return
}
Expand All @@ -419,13 +442,13 @@ private constructor(
val productId = productDetailJson.getString(PRODUCT_ID)
productDetailsMap[productId] = productDetailJson
}

} catch (e: Exception) {
/* swallow */
}
}
}


@AutoHandleExceptions
private fun onBillingSetupFinished(wrapperArgs: Array<Any>?, listenerArgs: Array<Any>?) {
if (listenerArgs.isNullOrEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ class InAppPurchaseBillingClientWrapperV5PlusTest : FacebookPowerMockTestCase()
val billingResult: Any = mock()
val proxy: Any = mock()
val purchase: Any = mock()
val productType: Any = InAppPurchaseUtils.IAPProductType.INAPP
val wrapperArgs = arrayOf(productType)
val purchaseList: List<*> = listOf(purchase)

val args = arrayOf(billingResult, purchaseList)
Expand All @@ -218,10 +220,11 @@ class InAppPurchaseBillingClientWrapperV5PlusTest : FacebookPowerMockTestCase()
eq(purchase),
)
).thenReturn(purchaseJsonStr)

val mockContext: Context = mock()
val inAppPurchaseBillingClientWrapperV5Plus =
InAppPurchaseBillingClientWrapperV5Plus.getOrCreateInstance(mockContext)
inAppPurchaseBillingClientWrapperV5Plus?.ListenerWrapper(null)?.invoke(
inAppPurchaseBillingClientWrapperV5Plus?.ListenerWrapper(wrapperArgs)?.invoke(
proxy,
Class.forName(exampleClassName)
.getMethod(METHOD_ON_QUERY_PURCHASES_RESPONSE),
Expand All @@ -236,6 +239,8 @@ class InAppPurchaseBillingClientWrapperV5PlusTest : FacebookPowerMockTestCase()
val billingResult: Any = mock()
val proxy: Any = mock()
val purchaseHistoryRecord: Any = mock()
val productType: Any = InAppPurchaseUtils.IAPProductType.INAPP
val wrapperArgs = arrayOf(productType)
val purchaseHistoryRecordList: List<*> = listOf(purchaseHistoryRecord)

val args = arrayOf(billingResult, purchaseHistoryRecordList)
Expand All @@ -246,10 +251,11 @@ class InAppPurchaseBillingClientWrapperV5PlusTest : FacebookPowerMockTestCase()
eq(purchaseHistoryRecord),
)
).thenReturn(purchaseHistoryRecordJsonStr)

val mockContext: Context = mock()
val inAppPurchaseBillingClientWrapperV5Plus =
InAppPurchaseBillingClientWrapperV5Plus.getOrCreateInstance(mockContext)
inAppPurchaseBillingClientWrapperV5Plus?.ListenerWrapper(null)?.invoke(
inAppPurchaseBillingClientWrapperV5Plus?.ListenerWrapper(wrapperArgs)?.invoke(
proxy,
Class.forName(exampleClassName)
.getMethod(METHOD_ON_PURCHASE_HISTORY_RESPONSE),
Expand Down

0 comments on commit 8575b3b

Please sign in to comment.