Issue
I have an issue retrieving product details, I have setup in my google play console this way:
And I have done the following:
myLog("MYAPP-TEST---1")
val purchasesUpdatedListener =
PurchasesUpdatedListener { billingResult, purchases ->
if (billingResult.responseCode ==
BillingClient.BillingResponseCode.OK
&& purchases != null
) {
for (purchase in purchases) {
// Process the purchases
myLog("MYAPP-TEST---")
}
} else if (billingResult.responseCode ==
BillingClient.BillingResponseCode.USER_CANCELED
) {
myLog("MYAPP-TEST---2")
// Purchase cancelled by user
} else {
myLog("MYAPP-TEST---3")
// Handle errors here
}
}
var billingClient = BillingClient.newBuilder(this)
.setListener(purchasesUpdatedListener)
.enablePendingPurchases()
.build()
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
// Connection successful
myLog("MYAPP-TEST---SUCCESS")
} else {
// Connection failed
}
}
override fun onBillingServiceDisconnected() {
// Connection to billing service lost
myLog("MYAPP-TEST---DISCONNECTED")
}
})
val productList: ArrayList<Product> = ArrayList()
productList.add(
Product.newBuilder()
.setProductId("poroductid1")
.setProductType(BillingClient.ProductType.SUBS)
.build()
);
productList.add(
Product.newBuilder()
.setProductId("poroductid2")
.setProductType(BillingClient.ProductType.SUBS)
.build()
);
productList.add(
Product.newBuilder()
.setProductId("poroductid3")
.setProductType(BillingClient.ProductType.SUBS)
.build()
);
productList.add(
Product.newBuilder()
.setProductId("poroductid4")
.setProductType(BillingClient.ProductType.SUBS)
.build()
);
val queryProductDetailsParams =
QueryProductDetailsParams.newBuilder()
.setProductList(productList)
.build()
processPurchases()
billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult,
skuDetailsList ->
if (skuDetailsList.isNotEmpty()) {
for (productDet in skuDetailsList) {
myLog("MYAPP-TEST----")
myLog(productDet.name)
}
// Process list of matching products
} else {
myLog("MYAPP-TEST---No product matches found")
// No product matches found
}
// Process the result
}
And I keep getting those debugs
2022-09-16 16:04:17.983 13457-13457/com.my.app D/MainActivity: MYAPP-TEST---1
2022-09-16 16:04:18.012 13457-13457/com.my.app D/MainActivity: MYAPP-TEST---No product matches found
2022-09-16 16:04:18.470 13457-13700/com.my.app D/MainActivity: MYAPP-TEST---SUCCESS
I also have publish my app so products should be "publicly" available (don't know if it is still needed, but I seen elsewhere it was).
So has you can see my product details request seams to be empty.
I am pretty new in kotlin / app developpement so I will probably need a lot of explaining.
Solution
Your setup succeeds after trying to retrieve the product list. You want to be sure that the setup succeeds before.
And this is what BillingClientStateListener
is for.
First you should put all your products retrieval code in a separate function :
fun retrieveProducts() {
val productList: ArrayList<Product> = ArrayList()
productList.add(
Product.newBuilder()
.setProductId("poroductid1")
.setProductType(BillingClient.ProductType.SUBS)
.build()
);
productList.add(
Product.newBuilder()
.setProductId("poroductid2")
.setProductType(BillingClient.ProductType.SUBS)
.build()
);
productList.add(
Product.newBuilder()
.setProductId("poroductid3")
.setProductType(BillingClient.ProductType.SUBS)
.build()
);
productList.add(
Product.newBuilder()
.setProductId("poroductid4")
.setProductType(BillingClient.ProductType.SUBS)
.build()
);
val queryProductDetailsParams =
QueryProductDetailsParams.newBuilder()
.setProductList(productList)
.build()
billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult,
skuDetailsList ->
if (skuDetailsList.isNotEmpty()) {
for (productDet in skuDetailsList) {
myLog("MYAPP-TEST----")
myLog(productDet.name)
}
// Process list of matching products
} else {
myLog("MYAPP-TEST---No product matches found")
// No product matches found
}
// Process the result
}
Afterwards, call your function in the BillingClientStateListener
onBillingSetupFinished
function :
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
// Connection successful
myLog("MYAPP-TEST---SUCCESS")
// This is where you can start retrieving your products
retrieveProducts()
} else {
// Connection failed
}
}
override fun onBillingServiceDisconnected() {
// Connection to billing service lost
myLog("MYAPP-TEST---DISCONNECTED")
}
})
The problem you faced is due to asynchronous actions : both your client setup and your purchases retrieval are asynchronous, meaning that they aren't executed on the same thread that your basic code.
To be sure to do things in the good order, you have to use those listeners the Billing library provides you with !
First, you want to setup your billing service. When done, the onBillingSetupFinished
callback is called. That's when you are sure you can go further !
This is a classical "problem" you will have to face in Android development, and the listeners system is a classical way of doing actions resulting from another action done in another thread than the main thread.
Answered By - Jeremy F
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.