Flutter | Getting Firebase Email Link Login Data - flutter

I have difficulty implementing the Email Link login with Firebase.
I send the email link using:
_firebaseAuth.sendSignInLinkToEmail(
email: email,
actionCodeSettings: ActionCodeSettings(
url: 'https://subdomain.example.com/user-auth', //<subdomain.example.com> = my real domain
handleCodeInApp: true,
androidInstallApp: true,
androidPackageName: 'com.example.app',
),
);
Email is sent and when clicking I open the link using the DynamicLink package:
void _handleDynamicLinks() {
FirebaseDynamicLinks.instance.onLink(onSuccess: _onSuccess);
}
Future<dynamic> _onSuccess(PendingDynamicLinkData data) async {
print('---onLink---');
// How to pass signIn link to `isSignInWithEmailLink` and `signInWithEmailLink` ???
// data.link returns `https://subdomain.example.com/user-auth` which is not the complete link
}
Every method I call on PendingDynamicLinkData data doesn't return the full dynamic link and isSignInWithEmailLink returns false!

Try this in your _handleDynamicLink function.
try {
FirebaseDynamicLinks.instance.onLink.listen((dynamicLink) {
final Uri? deepLink = dynamicLink.link;
if (deepLink != null) {
emailLinkService.handleLink(deepLink, _emailController.text);
FirebaseDynamicLinks.instance.onLink.listen((dynamicLink) {
final Uri? deepLink = dynamicLink.link;
emailLinkService.handleLink(deepLink!, _emailController.text);
}, onError: (e) async {
print(e.message);
});
}
}, onError: (e) async {
print(e.message);
});
final PendingDynamicLinkData? data =
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri? deepLink = data?.link;
print('deepLink :: $deepLink');
} catch (e) {
// you can print this error as well
}
And check if your url is the same as here:
And also add the Dynamic link as your custom Authorised domain like this:
Here is the handleLink method:
class EmailLinkService {
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<void> signInWithEmailAndLink(
{required String userEmail}) async {
var _userEmail = userEmail;
var acs = ActionCodeSettings(
url: Constants.firebaseProjectURL,
handleCodeInApp: true,
iOSBundleId: 'com.example....',
androidPackageName: 'com.example....',
try {
return await _auth
.sendSignInLinkToEmail(email: _userEmail, actionCodeSettings: acs);
} on FirebaseAuthException catch (e) {
}
void handleLink(Uri link, userEmail) async {
if (link != null) {
final UserCredential user =
await FirebaseAuth.instance.signInWithEmailLink(
email: userEmail,
emailLink: link.toString(),
);
} else {
print(" link is null");
}
}
}

Related

I'm getting errors for my controller listener in Flutter

I am building a password manager flutter application and I'm using Firestore database to store the data(passwords) entered by the users. I have created 4 different text fields on my Flutter application and on the firestore database, namely : title, email, userpassword and url.
I am getting some errors for my listeners.
void _titleControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final title = _titleController.text;
await _passwordsService.updatePassword(
documentId: password.documentId,
title: title,
);
}
void _emailControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final email = _emailController.text;
await _passwordsService.updatePassword(
documentId: password.documentId,
email: email,
);
}
void _userPasswordControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final userpassword = _userPasswordController.text;
await _passwordsService.updatePassword(
documentId: password.documentId,
userpassword: userpassword,
);
}
void _urlControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final url = _urlController.text;
await _passwordsService.updatePassword(
documentId: password.documentId,
url: url,
);
}
Errors: These 4 four errors are repeated for a total of 24 errors.
The named parameter 'url' is required, but there's no corresponding argument.
Try adding the required argument.
The named parameter 'email' is required, but there's no corresponding argument.
Try adding the required argument.
The named parameter 'userpassword' is required, but there's no corresponding argument.
Try adding the required argument.
The named parameter 'title' is required, but there's no corresponding argument.
Try adding the required argument.
update password() code(I'm not getting any errors here).
Future<void> updatePassword({
required String documentId,
required String title,
required String email,
required String userpassword,
required String url,
}) async {
try {
await passwords.doc(documentId).update({titleFieldName: title});
await passwords.doc(documentId).update({emailFieldName: email});
await passwords.doc(documentId).update({userpasswordFieldName: userpassword});
await passwords.doc(documentId).update({urlFieldName: url});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
Pay attention that when you are calling:
await _passwordsService.updatePassword(
documentId: password.documentId,
url: url,
);
You are not passing all required parameters. You have various calls to this method and each time you are calling it with different arguments.
I.E.
void _userPasswordControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final userpassword = _userPasswordController.text;
await _passwordsService.updatePassword( //// <----
documentId: password.documentId,
userpassword: userpassword,
);
}
The method updatePassword has five required arguments:
updatePassword({
required String documentId, /// <-------
required String title, /// <-------
required String email, /// <-------
required String userpassword, /// <-------
required String url, /// <-------
})
so you must pass all of them.
An example call could be:
await _passwordsService.updatePassword(
documentId: password.documentId,
userpassword: userpassword,
title: YOUR_TITLE,
url: YOUR_URL,
email: YOUR_EMAIL
);
In updatePassword method you specified title, email, userpassword and url as required.
You can make them optional:
Future<void> updatePassword({
required String documentId,
String? title,
String? email,
String? userpassword,
String? url,
}) async {
try {
if (title != null) await passwords.doc(documentId).update({titleFieldName: title});
if (email != null) await passwords.doc(documentId).update({emailFieldName: email});
if (userpassword != null) await passwords.doc(documentId).update({userpasswordFieldName: userpassword});
if (url != null) await passwords.doc(documentId).update({urlFieldName: url});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
I was able to solve the errors by splitting the updatePassword() code into 4 different functions. 1 function for each text field.
Future<void> updatePasswordTitle({
required String documentId,
required String title,
}) async {
try {
await passwords.doc(documentId).update({titleFieldName: title});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
Future<void> updatePasswordEmail({
required String documentId,
required String email,
}) async {
try {
await passwords.doc(documentId).update({emailFieldName: email});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
Future<void> updatePasswordUserpassword({
required String documentId,
required String userpassword,
}) async {
try {
await passwords.doc(documentId).update({userpasswordFieldName: userpassword});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
Future<void> updatePasswordUrl({
required String documentId,
required String url,
}) async {
try {
await passwords.doc(documentId).update({urlFieldName: url});
} catch (e) {
throw CouldNotUpdatePasswordException();
}
}
After creating the above 4 updatePassword functions. I made changes to the controller listeners. So, that they call their own updatePassword function.
void _titleControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final title = _titleController.text;
await _passwordsService.updatePasswordTitle(
documentId: password.documentId,
title: title,
);
}
void _emailControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final email = _emailController.text;
await _passwordsService.updatePasswordEmail(
documentId: password.documentId,
email: email,
);
}
void _userPasswordControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final userpassword = _userPasswordController.text;
await _passwordsService.updatePasswordUserpassword(
documentId: password.documentId,
userpassword: userpassword,
);
}
void _urlControllerListener() async {
final password = _password;
if (password == null) {
return;
}
final url = _urlController.text;
await _passwordsService.updatePasswordUrl(
documentId: password.documentId,
url: url,
);
}

Flutter Stripe paymentsheet is opening webpage (hooks.stripe.com) while processing payments

I am developing a flutter application which uses stripe for payments. I am using https://pub.dev/packages/flutter_stripe for this.
Everything is working fine but whenever I initiate payments I always get a webpage middleware (Screenshots attached). What am I doing wrong?
Here is my implementation in Flutter
Future<void> makePayment(String planName, String type) async {
Fluttertoast.showToast(msg: "initiating Payments, Please wait.");
ApiProvider provider = ApiProvider();
final tokenResponse = await provider
.getPaymentToken(PlanPayment(planName: planName, type: type));
if (tokenResponse != null) {`
var _service = locator<NavigationService>();
String secret = tokenResponse.clientSecret;
// make a get call from this url
Map<String, dynamic> paymentIntentData = Map();
await payment.Stripe.instance.initPaymentSheet(
paymentSheetParameters: payment.SetupPaymentSheetParameters(
merchantCountryCode: 'IN',
testEnv: true,
paymentIntentClientSecret: secret,
googlePay: true,
));
try {
// await Stripe.instance.handleCardAction(secret);
await payment.Stripe.instance.presentPaymentSheet().then((value) {});
await payment.Stripe.instance
.confirmPaymentSheetPayment()
.then((value) async {
// await _service.pushNamed(paymentStatus, args: {'isSuccess': true});
});
} catch (e) {
// await _service.pushNamed(paymentStatus, args: {'isSuccess': false});
print("Stripe error" + e.toString());
}
await provider
.confirmPayment(tokenResponse.transactionId)
.then((value) async {
await _service
.pushReplacementNamed(paymentStatus, args: {"isSuccess": value});
});
}
}
`
Maybe you have a webhook put in your account?
1)Provide valid Secret key
2)Provide valid Publisable key
3)Update flutterstripe pacakge
4)provide valid currency code to create stripe account country
ex :- stripe account create india to inr etc..
5)Right Way to implemet
- Main.dart to main method run app to implemet
ex :--
Stripe.publishableKey = "your publishable key ";
- create controller / method
code:-
Map<String, dynamic>? paymentIntentData;
Future<void> makePayment({amount}) async {
try {
paymentIntentData =
await createPaymentIntent(amount: amount, currency: 'INR');
if (paymentIntentData != null) {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
// applePay: true,
googlePay: const PaymentSheetGooglePay(merchantCountryCode: 'INR'),
merchantDisplayName: "PGA",
customerId: paymentIntentData!['customer'],
paymentIntentClientSecret: paymentIntentData!['client_secret'],
customerEphemeralKeySecret: paymentIntentData!['ephemeralkey'],
));
}
displayPaymentSheet();
} catch (err) {
logger.e(err);
}
}
void displayPaymentSheet() async {
try {
await Stripe.instance.presentPaymentSheet();
Get.snackbar("PaymentInfo", "Payment Successfully");
} on Exception catch (e) {
if (e is StripeException) {
logger.e(e, "Error From Stripe");
} else {
logger.e(e, "Unforeseen error");
}
} catch (e) {
logger.e("exeption === $e");
}
}
var id = "";
createPaymentIntent({amount, currency}) async {
try {
Map<String, dynamic> body = {
'amount': calculateAmount(amount: amount),
'currency': currency,
'payment_method_types[]': 'card'
};
var response = await http.post(
Uri.parse('https://api.stripe.com/v1/payment_intents'),
headers: {
'Authorization':
'Bearer YourSecretKey',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body,
);
if (response.statusCode == 200) {
var decode = jsonDecode(response.body);
logger.e(decode);
id = decode['id'];
return decode;
}
} catch (e) {
logger.e(e, "error charging user");
}
}
calculateAmount({amount}) {
logger.e(amount.round());
final a = (int.parse(amount.toString())) * 100;
logger.e(a.toString());
update();
return a.toString();
}
6) How to Access Stripe payment :-
ex :- any button click
ontap : (){
makePayment(
amount: "200")
}

"on HttpException catch (error)" desn't work in flutter

I made this code to handle error from the server Firebase with flutter :
This is the main function :
try {
if (_authMode == AuthMode.Login) {
print("log in");
await Provider.of<Auth>(context, listen: false)
.signIn(_authData['email'], _authData['password']);
} else {
await Provider.of<Auth>(context, listen: false)
.signUp(_authData['email'], _authData['password']);
}
} on HttpException catch (error) {
print("Check error");
if (error.toString().contains("EMAIL_EXISTS")) {
_ServerError =
"The email address is already in use by another account.";
}
if (error.toString().contains("TOO_MANY_ATTEMPTS_TRY_LATER")) {
_ServerError =
"We have blocked all requests from this device due to unusual activity.\n Try again later.";
} else {
_ServerError = "Something wrong. \n Try again later!";
}
} catch (error) {
print(error.toString() );
}
This is the called function :
Future<void> signIn(String? email, String? password) async {
const _url =
"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=APICODE";
_authentication(_url, email, password);}
Future<void> _authentication(
String _url, String? email, String? password) async {
try {
final _response = await http.post(Uri.parse(_url),
body: json.encode({
'email': email,
'password': password,
'returnSecureToken': true
}));
final _responseData = json.decode(_response.body);
if (_responseData['error'] != null) {
throw HttpException(_responseData['error']['message']);
}
} catch (error) {
throw error;
}}
But the problem is when the called function throw the HttpException error, I don't get it in the main function because the Catch doesn't work because I don't get the message "check error" in the panel ?!
this is the panel :
Can you help me please ?
The problem is I forgot to add return to called function :
Future<void> signIn(String? email, String? password) async {
const _url =
"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=APICODE";
return _authentication(_url, email, password);
}

How to get data from the CurrentUser on flutter Firebase Authentification

I have this Firebase Authentication Providers with who I can create an user, Sign In and Sign Out with the methods (only with email and password)
My problem I that in the UI I want to show data from the current User once the user has Sign In and I don't know how.
For example showing the email in a TextWidget or get the email as a variable for other stuff.
final firebaseAuthProvider = Provider<FirebaseAuth>((ref) {
return FirebaseAuth.instance;
});
class AuthenticationService {
final FirebaseAuth _firebaseAuth;
final Reader read;
AuthenticationService(this._firebaseAuth, this.read);
Stream<User?> get authStateChange => _firebaseAuth.authStateChanges();
Future<String> signIn({required String email, required String constrasena, required String nombreUsuario}) async {
try {
await _firebaseAuth.signInWithEmailAndPassword(
email: email,
password: constrasena,
);
return "Login Successful";
} on FirebaseAuthException catch (e) {
return e.message ?? 'Error';
}
}
Future<String> signUp({required String email, required String constrasena, required String nombreUsuario}) async {
try {
await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: constrasena,
);
read(addPerson(Person(nombre_de_usuario: nombreUsuario, email: email, videosVistos: 0)));
return "Signup Successful";
} on FirebaseAuthException catch (e) {
print(e.message);
return e.message ?? 'Error';
}
}
Future<void> signout() async {
await _firebaseAuth.signOut();
}
}
final authServicesProvider = Provider<AuthenticationService>((ref) {
return AuthenticationService(ref.read(firebaseAuthProvider), ref.read);
});
final authStateProvider = StreamProvider<User?>((ref) {
return ref.watch(authServicesProvider).authStateChange;
});
Thanks You!
You can use FirebaseAuth.instance.currentUser.
Example:
Get the user on your initState.
_user = FirebaseAuth.instance.currentUser;
And on your build method:
Text(_user?.email ?? 'No email')

Firebase Dynamic Links in flutter seems to recognize it was opened through a link but the link is always null

I'm using dynamic links ^0.7.0+1
When I press the link it loads the app, but doesn't navigate to the page I wanted, I've printed the link I receive, and it's always null, both when the app is in the background or not running at all.
Future<void> retrieveDynamicLink(BuildContext context) async {
List<String> linkData;
print('in retrieve link');
final PendingDynamicLinkData data =
await FirebaseDynamicLinks.instance.getInitialLink();
_handleDynamicLink(data);
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
linkData = await _handleDynamicLink(dynamicLink);
}, onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
});
if (data != null) {
AppRoutes.pushLinkEntryPage(
context: context, spreadsheetId: linkData[0], grade: linkData[1]);
}
}
static Future<List<String>> _handleDynamicLink(
PendingDynamicLinkData data) async {
String ssId = '';
String grade = '';
final Uri deepLink = data?.link;
print('deepLink = $deepLink');
if (deepLink == null) {
return null;
}
if (deepLink.queryParameters.containsKey('ss')) {
ssId = deepLink.queryParameters['ss'];
print('in retrieve link: ssID = $ssId');
}
if (deepLink.queryParameters.containsKey('gd')) {
grade = deepLink.queryParameters['gd'];
print('in retrieve link: gd = $grade');
}
return [ssId, grade];
}
I wasted couple of hours on this, and found the fix to be using the "Long dynamic link" instead of the "Deep link".
See attached image below:(This show details of the dynamic link in console)