'In App Purchase seems to be called multiple times
I implemented an In-App Purchase with the Play Billing Library 1.0 according to Google's tutorial. I have only 1 item for purchase and when it gets unlocked, I show a Toast message with the length Toast.LENGTH_SHORT. However, the Toast stays there for like 10 seconds, so I assume it gets called multiple times. It does NOT happen when I unlock it via queryPurchases (if someone bought it earlier and reinstalled the app in the meantime).
Anyone have an idea why the Toast stays so long / why it gets called multiple times?
Inside my BillingManager class:
@Override
public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases) {
if (responseCode == BillingClient.BillingResponse.OK) {
for (Purchase purchase : purchases) {
handlePurchases(purchase);
}
mBillingUpdatesListener.onPurchasesUpdated(mPurchases);
} else if (responseCode == BillingClient.BillingResponse.USER_CANCELED) {
} else {
}
}
public void handlePurchases(Purchase purchase) {
//here could be validation on own server
mPurchases.add(purchase);
}
Main Activity implements BillingUpdatesListener:
@Override
public void onPurchasesUpdated(List<Purchase> purchases) {
for (Purchase purchase : purchases) {
switch (purchase.getSku()) {
case "premium":
unlockPremium();
break;
}
}
}
public void unlockPremium() {
mPremiumUnlocked = true;
savePremiumUnlocked();
Toast.makeText(this, getResources().getString(R.string.premium_congrats), Toast.LENGTH_SHORT).show();
mAdView.setVisibility(GONE);
}
Solution 1:[1]
I don't know if this applies to your exact scenario, but we are experiencing the same thing and it is a bug on Google's end.
See https://issuetracker.google.com/issues/66054158 for more information.
Edit: I just saw that @goRGon posted the same thing :)
The example of multiple people in Spain isn't the same situation as what's described above. In the Spain scenario, the users are actually purchasing two copies of the IAP, so they are two separate receipts and the users should be rewarded with two copies of whatever they purchased. In the bug scenario, one single receipt is presented to the user twice so duplicates can actually be caught. But either way, back-end validation systems need to accommodate hackers/bugs in code that might cause the same receipt to be sent twice in a row.
Solution 2:[2]
If your subscription activity was closed and reopened multiple times within the same application process, then onPurchasesUpdated may be called multiple times if the PurchasesUpdatedListener somehow stays attached to the previous instances of billingClient and if the previous connections are still alive. I noticed that the number of times I closed and reopened the subscription activity, onPurchasesUpdated was called for the same amount after a successful launchBillingFlow.
To fix this I needed to end the connection when the activity is destroying, like this -
@Override
protected void onDestroy() {
super.onDestroy();
if (billingClient!= null) {
billingClient.endConnection();
}
}
Solution 3:[3]
Great answer and looking deep by @Kuffs!
Google will fix multiple calls soon: https://issuetracker.google.com/issues/66054158
However, your integration with billing flow should work even when onPurchasesUpdate was triggered multiple times, since it could happen anyway. For example, if somebody was buying in parallel on another device with the same @gmail account. And people in some countries (e.g. Spain) do share their @gmail accounts rather frequently with many friends and family members.
Please, check TrivialDrive_v2 implementation to get an idea, how handle such situations gracefully.
Solution 4:[4]
I hope It will help you
_purchaseUpdatedSubscription =
FlutterInappPurchase.purchaseUpdated.listen((productItem) {
print('purchase-updated: ${productItem}');
getDetails(productItem);
});
String orderId = '';
getDetails(PurchasedItem purchasedItem) {
if (purchasedItem != null) {
if (orderId != purchasedItem.orderId) {
orderId = purchasedItem.orderId;
print('productItem.transactionReceipt : ${purchasedItem.transactionReceipt}');
var decodedData = jsonDecode(purchasedItem.transactionReceipt);
print('purchaseState : ${decodedData['purchaseTime']}');
if (decodedData['purchaseState'] == 0) {
if(purchasedItem.productId == selected_package) {
print("Purchased successfully");
onPurchased(purchasedItem);
}
} else {
ShowMsg('Transaction Failed !, Something went wrong.');
}
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Faisal Khan |
| Solution 3 | goRGon |
| Solution 4 |
