I am using Google Play Billing Library 2.0.3 (implementation 'com.android.billingclient:billing:2.0.3'
) and it works fine for the most part, but for some users for the reasons unknown, querySkuDetailsAsync() method occasionally fails with BillingResponseCode.ERROR (6) error code...
Does anyone know anything about it? The reason of this error is not explained anywhere, other than it is a "Fatal error during the API action". Can anyone maybe tell why it might be happening?
edit: I am using the method as it is in the documentation (https://developer.android.com/google/play/billing/billing_library_overview):
public interface QuerySkuDetailsListener {
void onSuccess(List<SkuDetails> skuDetailsList);
void onErrorProductsHaveDifferentTypes();
void onBillingClientError(int error_code);
}
public void querySkuDetails(final QuerySkuDetailsListener querySkuDetailsListener, final Product... products) {
if (products.length < 1) {
//ERROR_NO_PRODUCTS_TO_QUERY
throw new NullPointerException();
}
String querySkuType = products[0].getSkuType();
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
List<String> skuList = new ArrayList<>();
for (Product product : products) {
skuList.add(product.getSku());
if (!product.getSkuType().equals(querySkuType)) {
//ERROR_SKU_TYPE_CANT_BE_DIFFERENT
querySkuDetailsListener.onErrorProductsHaveDifferentTypes();
return;
}
}
params.setSkusList(skuList).setType(querySkuType);
billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
querySkuDetailsListener.onSuccess(skuDetailsList);
}
else {
//ERROR QUERYING SKU DETAILS
querySkuDetailsListener.onBillingClientError(billingResult.getResponseCode());
}
}
});
}
Then I use it like this:
private void initiatePurchaseFlow(final Activity activity, @Nullable final Product oldProduct, final Product product, final JsonObject metadata, final InitiatePurchaseListener initiatePurchaseListener) {
//Check if billingClient is ready
if (billingClient.isReady()) {
querySkuDetails(new QuerySkuDetailsListener() {
@Override
public void onSuccess(List<SkuDetails> skuDetailsList) {
// Process the result.
BillingFlowParams.Builder flowParamsBuilder = BillingFlowParams.newBuilder();
flowParamsBuilder.setSkuDetails(skuDetailsList.get(0));
if (null != oldProduct) {
flowParamsBuilder.setOldSku(oldProduct.getSku());
flowParamsBuilder.setReplaceSkusProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_WITH_TIME_PRORATION);
}
BillingFlowParams flowParams = flowParamsBuilder.build();
int responseCode = billingClient.launchBillingFlow(activity, flowParams).getResponseCode();
if (responseCode == BillingClient.BillingResponseCode.OK) {
//SUCCESS, OK
...Rest of the irrelevant code...
}
else {
//ERROR_IN_LAUNCHING_BILLING_FLOW
dispenseInitiatePurchaseFlowError(activity, initiatePurchaseListener, InitiatePurchaseErrorCodes.ERROR_IN_LAUNCHING_BILLING_FLOW, getBillingClientErrorDescription(responseCode));
}
}
@Override
public void onErrorProductsHaveDifferentTypes() {
//ERROR_IN_QUERYING_SKU_DETAILS_PRODUCTS_HAVE_DIFFERENT_TYPES
dispenseInitiatePurchaseFlowError(activity, initiatePurchaseListener, InitiatePurchaseErrorCodes.ERROR_IN_QUERYING_SKU_DETAILS_PRODUCTS_HAVE_DIFFERENT_TYPES, getBillingClientErrorDescription(0));
}
@Override
public void onBillingClientError(int error_code) {
//ERROR_IN_QUERYING_SKU_DETAILS
dispenseInitiatePurchaseFlowError(activity, initiatePurchaseListener, InitiatePurchaseErrorCodes.ERROR_IN_QUERYING_SKU_DETAILS, getBillingClientErrorDescription(error_code));
}
}, product);
}
else {
//ERROR_BILLING_CLIENT_IS_NOT_READY
//Trying to reconnect once
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingResponse.OK) {
//launching again
initiatePurchaseFlow(activity, oldProduct, product, metadata, initiatePurchaseListener);
}
else {
// showing an error dialog
dispenseInitiatePurchaseFlowError(activity, initiatePurchaseListener, InitiatePurchaseErrorCodes.ERROR_BILLING_CLIENT_IS_NOT_READY, getBillingClientErrorDescription(billingResult.getResponseCode()));
}
}
@Override
public void onBillingServiceDisconnected() {
// showing an error dialog
}
});
}
}
edit: Could the users simply cheat? e.g. use a cracked google play store/other software that is messing with the purchases? Because I am not getting this error on any of the devices that I have, no matter what I do.
edit:
So far I found out that onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> purchases)
method of the billing client returns this error code (BillingResponseCode.ERROR
) if you use lucky patcher to crack the application, but I wasn't getting any errors in the querySkuDetailsAsync()
... Could this be related?
edit: Also I've created an issue in the google issuetracker, come support me there if you'd like. https://issuetracker.google.com/issues/139631105
For future reference and some other people suffering from this (like me at IAB 3.0.1), someone at the issue tracker bug that OP opened posted a comment about how we should react if we receive this code
Error 6 (https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#error) usually represents a transient error from our backend servers. This error code should trigger a retry which in most cases should succeed.
LINK: https://issuetracker.google.com/issues/139631105#comment11
example code:
@Override
public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) {
Utils.log("BILLING: onSkuDetailsResponse(). Result (" + billingResult.getResponseCode() + ") List size: " + (list == null ? "null" : list.size()));
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list != null) {
if (mSkuQueryErrorCounter > 0) mSkuQueryErrorCounter--;
// process the SkuDetail list...
}
} else {
// https://issuetracker.google.com/issues/139631105#comment11
mSkuQueryErrorCounter++;
if (mSkuQueryErrorCounter <= 2) scheduleUpdate(NOW);
else if (mSkuQueryErrorCounter < 5) scheduleUpdate(TEN_SECONDS);
else if (mSkuQueryErrorCounter < 10) scheduleUpdate(ONE_HOUR);
else scheduleUpdate(ONE_DAY);
}
}