I have set up in-app billing on an Android app (java). When I call launchBillingFlow
on the BillingClient
:
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
//the system displays the Google Play purchase screen
} else {
Log.e(TAG, "Billing failed: + " + billingResult.getDebugMessage());
}
This is what my onPurchasesUpdated
(from PurchasesUpdatedListener
) looks like:
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
&& purchases != null) {
for (Purchase purchase : purchases) {
for (String sku : purchase.getSkus()) {
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) {
if (skuConsumables.contains(sku)) {
handlePurchaseConsumable(purchase);
} else if (skuNonconsumables.contains(sku)) {
handlePurchaseNonconsumable(purchase);
}
}
}
}
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
billingServiceListener.receivePurchaseError();
} else {
// Handle any other error codes.
billingServiceListener.receivePurchaseError();
}
}
onPurchasesUpdated
is called six times, each time with a responseCode of OK
. Twice onPurchasesUpdated
is called with zero purchases, that's fine. What I am confused about is how to deal with the four times onPurchasesUpdated
is called with one purchase. And it seems as though each of these four purchase objects are indistinguishable - the same packageName
, acknowledged
, orderId
, productId
, purchaseState
, purchaseToken
, etc.
To complicate things, for consumable in-app billing, (these are consumable) I am then calling ConsumeResponseListener
and onConsumeResponse
is also returning four times, each time with responseCode of OK.
private void handlePurchaseConsumable(Purchase purchase) {
ConsumeParams consumeParams =
ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
ConsumeResponseListener listener = new ConsumeResponseListener() {
@Override
public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// Handle the success of the consume operation.
}
}
};
billingClient.consumeAsync(consumeParams, listener);
}
Is this behaviour seen by others? I am using static responses while in development, could this be the reason? If people are seeing this, how do you deal with this - do you keep track of what purchase you have attempted, and then when the first response is returned do you register that the purchase was successful and ignore subsequent times that onPurchasesUpdated
returns a purchase if you weren't expecting a payment? Though I've seen that Android permits cash purchases with enablePendingPurchases
, so that can't be a solution...