i am using https://pub.dev/packages/flutter_inapp_purchase this package for in-app-purchases. i sold credit but users can receive more credit then they paid, as shown in this video :
how can i fix this bug ? help me , please. thanks.
All relevant lines of code are in below;
code:
Future<void> initPlatformState() async {
await Purchases.setDebugLogsEnabled(true);
await Purchases.setup("RowkOdfhhydoMREZKRckltCNUNzJqgnj");
String platformVersion;
try {
platformVersion = await FlutterInappPurchase.instance.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
var result = await FlutterInappPurchase.instance.initConnection;
print('result: $result');
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
try {
String msg = await FlutterInappPurchase.instance.consumeAllItems;
print('consumeAllItems: $msg');
} catch (err) {
print('consumeAllItems error: $err');
}
_conectionSubscription =
FlutterInappPurchase.connectionUpdated.listen((connected) {
print('connected: $connected');
});
_purchaseUpdatedSubscription =
FlutterInappPurchase.purchaseUpdated.listen((productItem) {
// String deviceId = await PlatformDeviceId.getDeviceId;
dispose();
initPlatformState();
//FlutterInappPurchase.instance.finishTransaction(productItem);
if (productItem.productId == "oddinbetcredit10") {
print("CREDİT 10 !!!");
addCredit(deviceid, "10").then((value) => {
tipController.updateCredit(),
Fluttertoast.showToast(
msg: "Successfully loaded 10 credit !...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.SNACKBAR,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
)
});
} else if (productItem.productId == "oddinbetcredit20") {
print("CREDİT 20 !!!");
addCredit(deviceid, "20").then((value) => {
tipController.updateCredit(),
Fluttertoast.showToast(
msg: "20 credits successfully loaded !...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.SNACKBAR,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
)
});
} else if (productItem.productId == "oddinbetcredit50") {
print("CREDİT 50 !!!");
addCredit(deviceid, "50").then((value) => {
tipController.updateCredit(),
Fluttertoast.showToast(
msg: "50 credits successfully loaded !...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.SNACKBAR,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
)
});
} else if (productItem.productId == "oddinbetcredit100") {
print("CREDİT 100 !!!");
addCredit(deviceid, "100").then((value) => {
tipController.updateCredit(),
Fluttertoast.showToast(
msg: "100 crdits successfully loaded!...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.SNACKBAR,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
)
});
} else if (productItem.productId == "oddinbetcreditvip"){
isPremium = true;
Fluttertoast.showToast(
msg: "VIP successfully loaded!...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.SNACKBAR,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
);
}
});
_purchaseErrorSubscription =
FlutterInappPurchase.purchaseError.listen((purchaseError) {
print('purchase-error: $purchaseError');
});
}
Actually, this is a bug in this plugin and it is still open on Github
The reason why you are getting more credits is because the purchaseUpdated
listener receives multiple callbacks on iOS and hence your addCredit()
function is called multiple times.
As a workaround, you can use the transactionId as a flag and avoid calling the code inside the purchaseUpdated
listener multiple times.
Add a check
if(lastTransactionId!=productItem.transactionId)
And initialize the lastTransactionId outside the if
statement body
lastTransactionId = productItem.transactionId;
Complete code:
Declare a global variable
String lastTransactionId;
And then update your listener code with this
_purchaseUpdatedSubscription =
FlutterInappPurchase.purchaseUpdated.listen((productItem) {
// String deviceId = await PlatformDeviceId.getDeviceId;
if(lastTransactionId!=productItem.transactionId){ //Added this to avoid multiple callbacks for the same transaction
dispose();
initPlatformState();
//FlutterInappPurchase.instance.finishTransaction(productItem);
if (productItem.productId == "oddinbetcredit10") {
print("CREDİT 10 !!!");
addCredit(deviceid, "10").then((value) => {
tipController.updateCredit(),
Fluttertoast.showToast(
msg: "Successfully loaded 10 credit !...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.SNACKBAR,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
)
});
} else if (productItem.productId == "oddinbetcredit20") {
print("CREDİT 20 !!!");
addCredit(deviceid, "20").then((value) => {
tipController.updateCredit(),
Fluttertoast.showToast(
msg: "20 credits successfully loaded !...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.SNACKBAR,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
)
});
} else if (productItem.productId == "oddinbetcredit50") {
print("CREDİT 50 !!!");
addCredit(deviceid, "50").then((value) => {
tipController.updateCredit(),
Fluttertoast.showToast(
msg: "50 credits successfully loaded !...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.SNACKBAR,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
)
});
} else if (productItem.productId == "oddinbetcredit100") {
print("CREDİT 100 !!!");
addCredit(deviceid, "100").then((value) => {
tipController.updateCredit(),
Fluttertoast.showToast(
msg: "100 crdits successfully loaded!...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.SNACKBAR,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
)
});
} else if (productItem.productId == "oddinbetcreditvip"){
isPremium = true;
Fluttertoast.showToast(
msg: "VIP successfully loaded!...",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.SNACKBAR,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
);
}
}
lastTransactionId = productItem.transactionId; //finally initialize your lastTransactionId with productItem.transactionId, outside the if statement
});
PS: You should call the await FlutterInappPurchase.instance.initConnection;
method only once.
I hope this answer helps!