Closed alihassan143 closed 2 years ago
Same issue for me. First time the payment is done. Second time the screen with the code is disposed and I cant use setState or use context.
@shadysamir, @alihassan143 We work on reproducing it on our side, if you can download our sample and modify it to produce the above issue it will be helpful for us to fix it.
Running the example as is did not produce the issue. I was able to replicate the issue by creating a similar scenario to our app. In our app the user navigates to a payment screen with payment options. Tapping the card payment calls a Future with startCardPayment, after the callback setState there is a button that calls Navigator.pop to take the user back to the screen previous to payment screen with the payment result.
Starting with your example app I built a similar case with the code below. To reproduce the issue:
main.dart:
import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:flutter_paytabs_bridge/BaseBillingShippingInfo.dart';
import 'package:flutter_paytabs_bridge/IOSThemeConfiguration.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkApms.dart';
import 'package:flutter_paytabs_bridge/PaymentSdkConfigurationDetails.dart';
import 'package:flutter_paytabs_bridge/flutter_paytabs_bridge.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
const App({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
class Home extends StatelessWidget {
const Home({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
child: Text("Payment"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyApp(),
));
},
),
),
);
}
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _instructions = 'Tap on "Pay" Button to try PayTabs plugin';
@override
void initState() {
super.initState();
}
Future<PaymentSdkConfigurationDetails> generateConfig() async {
var billingDetails = BillingDetails("John Smith", "email@domain.com",
"+97311111111", "st. 12", "ae", "dubai", "dubai", "12345");
var shippingDetails = ShippingDetails("John Smith", "email@domain.com",
"+97311111111", "st. 12", "ae", "dubai", "dubai", "12345");
List<PaymentSdkAPms> apms = [];
apms.add(PaymentSdkAPms.STC_PAY);
var configuration = PaymentSdkConfigurationDetails(
profileId: "*profile id*",
serverKey: "*server key*",
clientKey: "*client key*",
cartId: "12433",
cartDescription: "Flowers",
merchantName: "Flowers Store",
screentTitle: "Pay with Card",
amount: 20.0,
showBillingInfo: true,
forceShippingInfo: false,
currencyCode: "EGP",
merchantCountryCode: "EG",
billingDetails: billingDetails,
shippingDetails: shippingDetails,
alternativePaymentMethods: apms);
var theme = IOSThemeConfigurations();
theme.logoImage = "assets/logo.png";
configuration.iOSThemeConfigurations = theme;
return configuration;
}
Future<void> payPressed() async {
FlutterPaytabsBridge.startCardPayment(await generateConfig(), (event) {
debugPrint("Mounted: $mounted");
setState(() {
if (event["status"] == "success") {
// Handle transaction details here.
var transactionDetails = event["data"];
print(transactionDetails);
} else if (event["status"] == "error") {
// Handle error here.
} else if (event["status"] == "event") {
// Handle events here.
}
});
});
}
Future<void> apmsPayPressed() async {
FlutterPaytabsBridge.startAlternativePaymentMethod(await generateConfig(),
(event) {
setState(() {
if (event["status"] == "success") {
// Handle transaction details here.
var transactionDetails = event["data"];
print(transactionDetails);
} else if (event["status"] == "error") {
// Handle error here.
} else if (event["status"] == "event") {
// Handle events here.
}
});
});
}
Future<void> applePayPressed() async {
var configuration = PaymentSdkConfigurationDetails(
profileId: "*Profile id*",
serverKey: "*server key*",
clientKey: "*client key*",
cartId: "12433",
cartDescription: "Flowers",
merchantName: "Flowers Store",
amount: 20.0,
currencyCode: "AED",
merchantCountryCode: "ae",
merchantApplePayIndentifier: "merchant.com.bunldeId",
simplifyApplePayValidation: true);
FlutterPaytabsBridge.startApplePayPayment(configuration, (event) {
setState(() {
if (event["status"] == "success") {
// Handle transaction details here.
var transactionDetails = event["data"];
print(transactionDetails);
} else if (event["status"] == "error") {
// Handle error here.
} else if (event["status"] == "event") {
// Handle events here.
}
});
});
}
Widget applePayButton() {
if (Platform.isIOS) {
return TextButton(
onPressed: () {
applePayPressed();
},
child: Text('Pay with Apple Pay'),
);
}
return SizedBox(height: 0);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('PayTabs Plugin Example App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('$_instructions'),
SizedBox(height: 16),
TextButton(
onPressed: () {
payPressed();
},
child: Text('Pay with Card'),
),
SizedBox(height: 16),
TextButton(
onPressed: () {
apmsPayPressed();
},
child: Text('Pay with Alternative payment methods'),
),
SizedBox(height: 16),
applePayButton()
])),
);
}
}
The issue persists even in release mode and also on iOS
@shadysamir we are currently working on fixing it
The issue is very critical if you change the state it works. Only once in whole app lifecycle if you try another payment it keeps loading and shows error if you destroy the app and open app then only one time you can be able to use paytab successfully
Hi @alihassan143, @shadysamir: The issue fixed, please upgrade to 2.1.7
@MuhamedAdly fixed in master. Tested against example from master and works perfectly. Still no 2.1.7 release on pub.dev, latest is 2.1.6. Using flutter_paytabs_bridge: 2.1.7
in pubspec fails. For now I used this in pubspec to use master in our project:
flutter_paytabs_bridge:
git:
url: https://github.com/paytabscom/flutter-sdk-bridge
ref: master
Sorry @shadysamir, you can use 2.1.7 now
The issue persists for startAlternativePaymentMethod()
Confirming that the issue is resolved with 2.1.7 for all payment methods
Hello when the app is restart the payment and other function after payment working correctly but when i do the second payment after one payment successful and after successful payment the function after one payment work perfectly but when i want to initiate the second payment the second payment is done but the event call back function is not performing the flutter give dispose the timer issue [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: setState() called after dispose(): _ServiceDetailsScreenState#74407(lifecycle state: defunct, not mounted) E/flutter (23070): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback. E/flutter (23070): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree. E/flutter (23070): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
![image](https://user-images.githubusercontent.com/71745182/137444712-f0604e1e-380f-4d87-b49e-85d1a5f9ff2b.png)