1

Getting an empty list when fetching with querySkuDetails()?

Kevin Germain
  • 471
  • 3
  • 6

1 Answers1

0

So in case you've been having this issue lately, where you want to fetch your Google Play Console list of SkuDetail, maybe to show the price of one of the SkuDetail and show it to the user has it was in my case or to display some other information about a SkuDetail from your Google Play Console merchant account. Anyways, here's what's worked for me:

First you need to add this to your build.gradle app file:

implementation "com.android.billingclient:billing-ktx:4.0.0"

Then Inside of my Fragment's ViewModel, I did the following:


class MainViewModel(application: Application) : AndroidViewModel(application) {

private val billingClient by lazy {
        BillingClient.newBuilder(application.applicationContext)
            .setListener(purchasesUpdatedListener)
            .enablePendingPurchases()
            .build()
    }

/** 
@param result Returns true if connection was successful, false if otherwise 
*/
private inline fun billingStartConnection(crossinline result: (Boolean) -> Unit) {
        billingClient.startConnection(object : BillingClientStateListener {
            override fun onBillingSetupFinished(billingResult: BillingResult) {
                if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
                    // The BillingClient is ready. You can query purchases here.
                    result(true)
                }
            }

            override fun onBillingServiceDisconnected() {
                // Try to restart the connection on the next request to
                // Google Play by calling the startConnection() method.
                result(false)
            }
        })
    }

sealed class BillingClientObserver {
        object Loading : BillingClientObserver()
        object ClientDisconnected : BillingClientObserver()
        object HasNoPurchases : BillingClientObserver()
        object HasNoAdsPrivilege : BillingClientObserver()
        object UserCancelledPurchase : BillingClientObserver()
        data class UnexpectedError(val debugMessage: String = "") : BillingClientObserver()
    }

private val _billingClientObserver: MutableStateFlow<BillingClientObserver> =
        MutableStateFlow(BillingClientObserver.Loading)
    val billingClientObserver: StateFlow<BillingClientObserver> = _billingClientObserver

suspend fun checkSkuDetailById(productId: String) =
        billingStartConnection { billingClientReady ->
            if (billingClientReady) {
                val skuList = ArrayList<String>()
                skuList.add(productId)
                val params = SkuDetailsParams.newBuilder()
                params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
                viewModelScope.launch(Dispatchers.Main) {
                    val skuDetailList = withContext(Dispatchers.IO) {
                        billingClient.querySkuDetails(params.build())
                    }
                    skuDetailList.skuDetailsList?.let {
                        Timber.d("Timber> List<SkuDetails>: $it")
                        if (it.isNotEmpty()) {
                            val skuDetails: SkuDetails = it[0]
                            _goAdsFreePricing.value = skuDetails.price
                        } else {
                            _billingClientObserver.value =
                                BillingClientObserver.UnexpectedError(context.getString(R.string.unable_to_get_price_msg))
                        }
                    } ?: run {
                        _billingClientObserver.value =
                            BillingClientObserver.UnexpectedError(context.getString(R.string.unable_to_get_price_msg))
                    }
                }
            } else {
                _billingClientObserver.value =
                    BillingClientObserver.UnexpectedError(context.getString(R.string.unable_connect_to_play_store))
            }
        }
}

The most important thing to do for the

BillingClient.querySkuDetails(SkuDetailsParams.builder())

to be successful, is to first establish a successful connection through the

BillingClient.startConnection( listener: BillingClientStateListener)

then do the query on the background thread, very important that the

querySkuDetails()

happens in the background thread as it is made to fail if done on the

@MainThread

then listen for its result on the

@MainThread

like in the above example.

Kevin Germain
  • 471
  • 3
  • 6