I've been implementing for the first time in-app billing in my app and even if all the code is correct, it is not working!
I have a BillingManager.java
public class BillingManager implements PurchasesUpdatedListener {
private static final String TAG = "BillingManager";
private final BillingClient mBillingClient;
private final Activity mActivity;
String base64Key = "mykey";
private static Context myCxt;
private String mAdRemovalPrice;
private static final String ITEM_SKU_ADREMOVAL = "myskuid";
public int billingResult;
public BillingManager(Activity activity) {
mActivity = activity;
mBillingClient = BillingClient.newBuilder(mActivity).setListener(this).build();
mBillingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponse) {
if (billingResponse == BillingClient.BillingResponse.OK) {
Log.i(TAG, "onBillingSetupFinished() good response: " + billingResponse);
List skuList = new ArrayList<>();
skuList.add(ITEM_SKU_ADREMOVAL);
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
mBillingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(int responseCode, List skuDetailsList) {
// Process the result.
if (responseCode == BillingClient.BillingResponse.OK
&& skuDetailsList != null) {
for (Object skuDetailsObject : skuDetailsList) {
SkuDetails skuDetails = (SkuDetails) skuDetailsObject;
String sku = skuDetails.getSku();
String price = skuDetails.getPrice();
if (ITEM_SKU_ADREMOVAL.equals(sku)) {
mAdRemovalPrice = price;
}
}
}
}
});
} else {
Log.w(TAG, "onBillingSetupFinished() error code: " + billingResponse);
}
}
@Override
public void onBillingServiceDisconnected() {
Log.w(TAG, "onBillingServiceDisconnected()");
}
});
}
@Override
public void onPurchasesUpdated(int responseCode, List<Purchase> purchases) {
if (responseCode == BillingClient.BillingResponse.OK
&& purchases != null) {
for(Purchase purchase: purchases) {
// When every a new purchase is made
// Here we verify our purchase
Log.i(TAG, "onPurchasesUpdated() ourchase ok response: " + responseCode);
if (!verifyValidSignature(purchase.getOriginalJson(), purchase.getSignature())) {
// Invalid purchase
// show error to user
myCxt = MainActivity.proContext;
Toast.makeText(myCxt, myCxt.getString(R.string.purchase_err), Toast.LENGTH_LONG).show();
Log.i(TAG, "Got a purchase: " + purchase + "; but signature is bad. Skipping...");
return;
} else {
// purchase is valid
// Perform actions
myCxt = MainActivity.proContext;
Toast.makeText(myCxt, myCxt.getString(R.string.purchase_done), Toast.LENGTH_LONG).show();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(myCxt);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("isPro", true);
editor.apply();
}
}
} else if (responseCode == BillingClient.BillingResponse.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
Log.i(TAG, "onPurchasesUpdated() user canceled response: " + responseCode);
} else {
// Handle any other error codes.
Log.i(TAG, "onPurchasesUpdated() error response: " + responseCode);
}
}
public void startPurchaseFlow() {
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setSku(ITEM_SKU_ADREMOVAL)
.setType(BillingClient.SkuType.INAPP)
.build();
mBillingClient.launchBillingFlow(mActivity, flowParams);
Log.i(TAG, "StartPurchaseFlow called");
}
private boolean verifyValidSignature(String signedData, String signature) {
try {
return Security.verifyPurchase(base64Key, signedData, signature);
} catch (IOException e) {
Log.e(TAG, "Got an exception trying to validate a purchase: " + e);
return false;
}
}
And then i call it like this in my App menu:
if (id == R.id.action_pro) {
BillingManager mbilling = new BillingManager(MainActivity.this);
mbilling.startPurchaseFlow();
return true;
}
Actually it turns out that if I read the logs in debugging mode seems that onPurchasesUpdated() method throws the error -1 as response code! So this means that the responsecode is -1 which according to Java documentation is a generic error in http protocol... Why am I getting this?
The code seems pretty good even if compared to others or to guides found online. Does anyone have any suggestions?
Please make sure your billing client is initialized before you start the purchaseflow.
response code -1 indicates billingclient disconnected