I'm New to flutter and dart mobile app development. how to implement forgot password and send verification mail in flutter/dart development or is there any way to implement to send mail.
I don't think there is any way to send an email from your flutter application. This is something I would definitely implement on a backend server.
I would implement a 'forgot password' button in flutter, which triggers a http call to the backend which then triggers the password generation and email sending.
Yes there are some ways. The most common would be to use firebase as a backend server handling these requests.
You could do it like this
Add these packages to your flutter apps pubspec.yaml file
// latest version
firebase_core: ^1.17.0
firebase_auth: ^3.3.18
On forgot password button click
once you've completed the logic necessary before making the request, call this function
sendResetEmail(String email, BuildContext context) async {
final FirebaseAuth _auth = FirebaseAuth.instance;
try {
await _auth.sendPasswordResetEmail(email: email);
Timer(
const Duration(seconds: 3),
() => CustomWidgets().moveToPage(
page: const Home(), context: context, replacement: true),
);
} catch (e) {
// error handling here
}
}
This will send an email from firebase to the selected email to reset password.
On email verification request
Once the logic is over, call this function.
bool _isEmailVerified = false;
Timer? timer;
final FirebaseAuth _auth = FirebaseAuth.instance;
the initstate method
#override
void initState() {
_isEmailVerified = _auth.currentUser!.emailVerified;
if (!_isEmailVerified) {
sendEmailVerificationForUser();
timer = Timer.periodic(const Duration(seconds: 5), (timer) {
emailVerificationStatus(context);
});
}
email verification check function
emailVerificationStatus(BuildContext context) async {
try {
await _auth.currentUser!.reload();
setState(() {
_isEmailVerified = _auth.currentUser!.emailVerified;
});
} catch (e) {
// handle the error here
}
setState(() {
_isEmailVerified = _auth.currentUser!.emailVerified;
});
if (_isEmailVerified) {
timer?.cancel();
// and move to next page
}}
send email verification function
Future sendEmailVerificationForUser() async {
try {
await FirebaseAuth.instance.currentUser!.sendEmailVerification();
} catch (e) {
// error handling}
Related
main.dart
WidgetsFlutterBinding.ensureInitialized();
Stripe.publishableKey = stripePublishableKey;
Stripe.merchantIdentifier = 'emailID';
await Stripe.instance.applySettings();
Initiate Payment
Future<void> initPaymentSheet({
required String? price,
}) async {
try {
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
// Main params
paymentIntentClientSecret: clientSecret,
customerId: customerId,
customerEphemeralKeySecret: ephemeralKey,
// Merchant Name
merchantDisplayName: 'TEST',
// Extra params
applePay: const PaymentSheetApplePay(
merchantCountryCode: 'US',
),
googlePay: const PaymentSheetGooglePay(
merchantCountryCode: 'US',
testEnv: true,
),
style: ThemeMode.system,
),
);
} catch (e) {
rethrow;
}
}
/// Display the payment sheet.
Future<void> confirmPayment({required String price}) async {
try {
await initPaymentSheet(price: price);
// Present Payment sheet to user for payment
await Stripe.instance.presentPaymentSheet();
// Book the request.
bookingRequest();
} on Exception catch (e) {
if (e is StripeException) {
// displaySnackBar(
// 'Error!', 'Error from Stripe: ${e.error.localizedMessage}');
log('Error from Stripe: ${e.error.localizedMessage}');
print('Error from Stripe: ${e.error.localizedMessage}');
displaySnackBar('Error!', 'Something went wrong!, \nPlease try again.');
} else {
log('Error from Stripe: $e');
displaySnackBar('Error!', 'Something went wrong!, \nPlease try again.');
}
}
}
This confirmPayment() is called on Button click.
It will wait for Init the payment sheet.
After that presentPaymentSheet called to present the Payment sheet.
In Android, It's working fine.
In iOS, it's showing error like: No payment sheet has been initialized yet
Already Raised the Issue on the plugin Repo.
https://github.com/flutter-stripe/flutter_stripe/issues/850
✅ Solved:
Okay, the problem was in our backend response
when we were generating EphemeralKey, our backend dev was returning ephemeralKey["id"] instead of ephemeralKey["secret"] as a ephemeralKey.
I changed the EphemeralKey
from this
paymentIntentDTO.setEphemeralKey(ephemeralKey.getId());
to this
paymentIntentDTO.setClientSecret(paymentIntent.getClientSecret());
see ephemeralKey is different.
ephemeralKey["id"] is work fine in android app for stripe payment but on IOS ephemeralKey["id"] will not working
it was showing Error from Stripe: No payment sheet has been initialised yet
i changed ephemeralKey["id"] to ephemeralKey["secret"] as a ephemeralKey and now it working fine on both device.
I got this error when i call verifyPhoneNumber method:
My code works fine in android. Only in IOS it throws me this error. I checked a lot of issues on stackoverflow and github and have made sure that my GoogleService-Info.plist is in the right folder. I imported GoogleService-Info.plist through Xcode only and it is also added in CopyBundleResources section in Xcode-> Runner -> BuildPhases. Also a lot of places I saw that I need to add REVERSED_CLIENT_ID in URL Types in Xcode. Done this and also checked Info.plist that my REVERSED_CLIENT_ID is added correctly.
I have done everything but still don't know what is causing the issue.
My code for mobile auth:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:[**package_name**]/functions/typedef.dart';
import 'package:[**package_name**]/helpers/log_helper.dart';
class MobileAuth{
MobileAuth(
this.mobileNumber,
this.afterCodeSent,
this.verificationCompleted,
this.verificationFailed,
this.autoTimeout,
this.ifOtpFailed,
this.afterOtpSend);
final String mobileNumber;
final AfterCodeSent afterCodeSent;
final PhoneAuthVerificationCompleted verificationCompleted;
final PhoneAuthVerificationFailed verificationFailed;
final AuthFailedMessage autoTimeout;
final AuthFailedMessage ifOtpFailed;
final AfterOtpSend afterOtpSend;
FirebaseAuth auth = FirebaseAuth.instance;
/// to sent the code to the given mobile number
void initialAuth() async{
await auth.verifyPhoneNumber(
phoneNumber: mobileNumber,
verificationCompleted: (PhoneAuthCredential credential) {
verificationCompleted(credential);
},
verificationFailed: (FirebaseAuthException e) {
verificationFailed(e);
},
codeSent: (String verificationId, int? resendToken) {
afterCodeSent(verificationId, resendToken ?? 0);
},
timeout: const Duration(seconds: 15),
codeAutoRetrievalTimeout: (String verificationId) {
autoTimeout(verificationId);
},
);
}
/// check otp by submitting to the auth api
void verifyOtp(String smsCode, String verificationId) async{
// Create a PhoneAuthCredential with the code
PhoneAuthCredential credential = PhoneAuthProvider.credential(verificationId: verificationId, smsCode: smsCode);
// Sign the user in (or link) with the credential
try{
UserCredential userCredential = await auth.signInWithCredential(credential);
LogHelper.log("After sending OTP: ${userCredential.user?.uid}");
afterOtpSend(userCredential);
}catch(e){
LogHelper.log("After sending OTP ${e.toString()}");
ifOtpFailed(e.toString());
}
}
void resendVerificationCode(int token) {
auth.verifyPhoneNumber(
forceResendingToken: token,
phoneNumber: mobileNumber,
verificationCompleted: (PhoneAuthCredential credential) {
verificationCompleted(credential);
},
verificationFailed: (FirebaseAuthException e) {
verificationFailed(e);
},
codeSent: (String verificationId, int? resendToken) {
afterCodeSent(verificationId , resendToken ?? 0);
},
timeout: const Duration(seconds: 60),
codeAutoRetrievalTimeout: (String verificationId) {
autoTimeout(verificationId);
},
);
}
}
And i call this in my statefull widget init method like this:
#override
void initState(){
String mobileNumber = "${widget.countryCode} ${widget.phoneNumber}";
mobileAuth = MobileAuth(mobileNumber, afterCodeSent,
verificationCompleted, verificationFailed, autoTimeout, ifOtpFailed, afterOtpSend);
sendOtpToPhone();
}
void sendOtpToPhone(){
mobileAuth.initialAuth();
}
The code works fine in android debug and release mode, so I only have this issue in IOS. Crashes when I call sendOtpToPhone(); -> mobileAuth.initialAuth(); -> auth.verifyPhoneNumber();
I have know for sure that auth.verifyPhoneNumber(); is only causing the error, because if I comment that segment of code then no crash is happening.
Also have tried flutter clean and i am using firebase_auth: 3.3.16 . Also tried it with 3.3.14.
I'm trying to use phone Authentication and it's working as expected on Android, but on iOS I always get Token mismatch and don't receive a code.
other Firebase services like cloud firestore and email Auth are working fine on iOS.
I made sure of the following:
-APN key is added in Firebase
-Google Services file is updated
-Background Modes and Push Notification capabilities are on
the error message is from PhoneVerificationFailed
Future<void> _verifyPhoneNumber() async {
setState(() {
_message = '';
});
final PhoneVerificationCompleted verificationCompleted =
(AuthCredential phoneAuthCredential) async {
await _auth.signInWithCredential(phoneAuthCredential);
setState(() {
_message = 'Received phone auth credential: $phoneAuthCredential';
});
};
final PhoneVerificationFailed verificationFailed =
(AuthException authException) {
setState(() {
_message = '********************\n\n'
'Phone number verification failed. Code: ${authException.code}.'
'\n Message: ${authException.message}'
'\n\n********************';
});
};
final PhoneCodeSent codeSent =
(String verificationId, [int forceResendingToken]) async {
_verificationId = verificationId;
setState(() {
_message = 'waiting for code';
//waitingCode = true;
});
};
final PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
(String verificationId) {
_verificationId = verificationId;
};
try {
await _auth.verifyPhoneNumber(
phoneNumber: number,
timeout: const Duration(seconds: 30),
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
} catch (e) {
print('Error is $e');
}
}
and I'm getting these messages from log
Userinfo {
"com.google.firebase.auth" = {
warning = "This fake notification should be forwarded to Firebase Auth.";
};
}
UserDate : {
"com.google.firebase.auth" = {
warning = "This fake notification should be forwarded to Firebase Auth.";
};
}
UserDate Json : {
"com.google.firebase.auth" : {
"warning" : "This fake notification should be forwarded to Firebase Auth."
}
}
flutter:
TRUE
flutter: Call Back {
"com.google.firebase.auth" : {
"warning" : "This fake notification should be forwarded to Firebase Auth."
}
}
I understand it's too late in answering this. But I also faced the same error recently. I fixed the issue on iOS. Your entire configuration must be valid. There are two settings you need to make.
Remove any method swizzling variable from GoogleService-info.plist
i.e. remove FirebaseAppDelegateProxyEnabled property from plist
In AppDelegate.swift, override this method and set the following
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
Messaging.messaging().apnsToken = deviceToken
}
It is mentioned at https://firebase.google.com/docs/cloud-messaging/ios/client#token-swizzle-disabled
I am using firebase_messaging: ^6.0.16 and the above settings worked
Changing the Firebase Auth version from 0.14.0 to
firebase_auth:
git:
url: https://github.com/collinjackson/plugins.git
ref: 441417c2fed0ff26bf84a49ab2c5ffd2aa5487de
path: packages/firebase_auth
fixed my issue.
see https://github.com/flutter/flutter/issues/35267 for more details
I'm building a flutter app which needs to send user agent information along with the http request. I'm using http dart package to send requests. How to get user agent string in flutter and use it with http package?
I done it by calling native methods in flutter. First you have to add method channel in android Main Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodChannel.MethodCallHandler() {
#Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
if (call.method.equals("getUserAgent")) {
result.success(System.getProperty("http.agent"));
} else {
result.notImplemented();
}
}
});
}
Then getUserAgent() method can be called in flutter like below
Future<String> _getUserAgent() async {
try {
return await platform.invokeMethod('getUserAgent');
} catch (e) {
return 'Unknown';
}
}
You can get it in a cross-platform way by using the flutter_user_agent library: https://pub.dev/packages/flutter_user_agent.
import 'package:flutter_user_agent/flutter_user_agent.dart';
...
String ua = await FlutterUserAgent.getPropertyAsync('userAgent');
this worked for me by using flutter_user_agent library: https://pub.dev/packages/flutter_user_agent
as mentioned above
String _userAgent = await FlutterUserAgent.getPropertyAsync('userAgent');
final _response = await http.get(_url, headers: {
'Content-Type': 'application/json',
'Accept-Charset': 'utf-8',
'User-Agent': '${_userAgent.toLowerCase()}',
});
Found a library that does it. It would be interesting to look at what the library does, i don't think it's needed to implement a library for that.
https://pub.dartlang.org/packages/user_agent
An example on how you would use it:
main() async {
app.get('/', (req, res) async {
var ua = new UserAgent(req.headers.value('user-agent'));
if (ua.isChrome) {
res.redirect('/upgrade-your-browser');
return;
} else {
// ...
}
});
}
Alternatively, if you want to add a user-agent to the http client, you can do it this way:
Future<http.Response> fetchPost() {
return http.get(your_url,
// Send user-agent header to your backend
headers: {HttpHeaders.userAgentHeader: "your_user_agent"},
);
}
You can look at HttpHeadersto see the full list of predefined headers, although headers take a map, you could create your own header if you want.
I've been developing an app with React Native (with Expo) and Firebase on the backend. When running the project through Expo client on the iPhone, I can normally login with email and password and then fetch data from Firebase database. But when I login with Facebook, database read hands and it does not resolve anything. Important parts of the code look following:
firebase.initializeApp(firebaseConfig);
// This works everywhere
export const login = async (email, password) => {
await firebase.auth().signInWithEmailAndPassword(email, password);
const userId = firebase.auth().currentUser.uid;
return userId + '';
};
export const loginByFacebook = async () => {
const { type, token } = await Expo.Facebook.logInWithReadPermissionsAsync(FB_APP_ID, {
permissions: ['public_profile'],
});
if (type === 'success') {
const credential = firebase.auth.FacebookAuthProvider.credential(token);
try {
await firebase.auth().signInAndRetrieveDataWithCredential(credential);
} catch (error) {
console.log('cannot login ', error);
}
}
};
export const readData = (key) => {
console.log('getWins ');
const userId = firebase.auth().currentUser.uid;
return firebase
.database()
.ref(`/${key}/${userId}`)
.once('value');
};
...
class PostList extends React.Component {
async componentDidMount() {
// it normally resolves when logged with email & password,
// resolves with facebook auth on iPhone simulator
// does not resolve with facebook auth on Expo client on iPhone
const data = await readData('posts');
}
}
However, what is really strange, that it does not work on iPhone + Expo client, but does on the iPhone simulator. The crucial part is in the async componentDidMount().
Database config is still in the dev mode (allow all read & writes):
{
"rules": {
".read": true,
".write": true
}
}
I've used the following guides: https://docs.expo.io/versions/latest/sdk/facebook
https://docs.expo.io/versions/latest/guides/using-firebase#listening-for-authentication
Are there any more prerequisites that I've forgotten to setup? Or Expo client has limitations in terms of properly handling calls with Facebook auth?