FirabaseAuth can't catch exception in Flutter - firebase

I'm working on a signup screen for my app. I implemented firebase and can authenticate user and save some user info into firebase database succesfully. I started to check if userName field is empty or not. But firebase sometimes can not catch exception about bad formatted email address. It works for password (min 6 char) everytime but sometimes work for email. I can't find any solution. Here is my code. Is there anybody who have an idea?
onPressed: () async {
if (validateName(userName) && validateEmail(email)) {
setState(() {
showSpinner = true;
});
try {
final newUser =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
//get name and update user profile
UserUpdateInfo userUpdateInfo = UserUpdateInfo();
userUpdateInfo.displayName = userName;
FirebaseUser user = await _auth.currentUser();
await user.updateProfile(userUpdateInfo);
await user.reload();
Navigator.pushNamed(context, NavigationScreen.id);
}
setState(() {
showSpinner = false;
});
} on PlatformException catch (e) {
setState(() {
showSpinner = false;
});
Fluttertoast.showToast(
msg: e.message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 3,
backgroundColor: Colors.white,
textColor: Colors.red,
fontSize: 18.0,
);
}
} else {
Fluttertoast.showToast(
msg: 'You must ente all information',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 3,
backgroundColor: Colors.white,
textColor: Colors.red,
fontSize: 18.0,
);
}
},
//name TextField validation
bool validateName(String name) {
if (name != null && name.length > 2) {
return true;
} else {
return false;
}
}
//email TextField validation
bool validateEmail(String email) {
if (email != null) {
return true;
} else {
return false;
}
}

createUserWithEmailAndPassword returns a Future<AuthResult>, to catch the error you can do the following:
final newUser = await _auth.createUserWithEmailAndPassword(email: email, password: password).catchError((err) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Error"),
content: Text(err.message),
actions: [
FlatButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
Using catchError, it will handles errors emitted by this Future, and then showDialog will display a dialog with the error.

Related

Can't register user in firebase (firebase_auth/unknown: null)

I am registering a user in firebase and each time I try to register it shows me the mentioned error and donot send credentials to the firebase. Although it is getting the credentials from the firebase for login but shows error while storing values in firebase. Below is the code for only register that is getting the email address and password. I have another question that like password and email how could I store other details in firebase e.g Age, Gender etc. Kindly help me go through this.
class _ClientRegistrationScreenState extends State<ClientRegistrationScreen> {
bool showSpinner = false;
final _auth = FirebaseAuth.instance;
File image;
//final ImagePicker _picker = ImagePicker();
String password;
String confirmPassword;
String email;
String name;
bool _passwordVisible = false;
bool _confirmPasswordVisible = false;
#override
void initState() {
_passwordVisible = false;
_confirmPasswordVisible = false;
}
final _formKey = GlobalKey<FormState>();
Expanded(
child: Center(
child: TextFormField(
validator: (value) {
if (value == null || value.isEmpty) {
return '*Email Address Required';
}
return null;
},
),
),
),
),
Expanded(
child: Center(
child: TextFormField(
onChanged: (value){
password = value;
},
validator: (value) {
if (value == null || value.isEmpty) {
return '*Password Required';
}
if (password != confirmPassword) {
return 'Password Donot Match';
}
return null;
},
onPressed: () {
setState(() {
_passwordVisible = !_passwordVisible;
});
},
),
),
),
),
),
Expanded(
child: Center(
child: TextFormField(
onChanged: (value){
confirmPassword = value;
},
validator: (value) {
if (value == null || value.isEmpty) {
return '*Confirm Password';
}
if (password != confirmPassword) {
return 'Password Donot Match';
}
return null;
},
onPressed: () {
setState(() {
_confirmPasswordVisible = !_confirmPasswordVisible;
});
},
),
),
),
),
),
RoundedButton(
colour: Colors.yellow,
opColour: Colors.yellow.withOpacity(0.2),
title: 'Register',
buttonTextColor: Colors.black,
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() {
showSpinner = true;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Processing Data')),
);
}
try {
final newUser = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if(newUser!=null){
Navigator.pushNamed(context, MainEmployeeScreen.id);
print(name);
}
setState(() {
showSpinner = false;
});
}
catch(e){
print(e);
}
}
),
Did you initialize firebase in main function?
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}

Flutter Sign In how to show FirebaseAuthException message with Snackbar

I made a login page and auth with firebase, In this case at Login page i want to validate form, if user input wrong Email or Password than FirebaseAuthException massage to be shown on snackbar. I follow saveral tutorial like this , but after i try is just getting some FirebaseAuthException massege on console and app get freez not printed on snackbar. I will appreciate if someone help me through this.
This is my Authentication Service
class AuthenticationService with ChangeNotifier {
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
//AuthResultStatus _status;
bool _loggedIn = false;
bool get loggedIn => _loggedIn;
String userUid;
String get getUserUid => userUid;
Stream<User> get authStateChanges => firebaseAuth.authStateChanges();
Future<String> logIntoAccount(String email, String password) async {
try {
UserCredential userCredential = await firebaseAuth
.signInWithEmailAndPassword(email: email, password: password);
_loggedIn = true;
User user = userCredential.user;
userUid = user.uid;
print(userUid);
notifyListeners();
return "Signed In";
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
return 'No user found for that email.';
} else if (e.code == 'wrong-password') {
return "Wrong password provided for that user.";
} else {
return 'Something Went Wrong.';
}
}
}
and this the Button on LoginPage
Widget buildLoginBtn() {
return Padding(
padding: EdgeInsets.only(top: 7),
child: Column(
children: [
_isSubmitting == true
? CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation(Theme.of(context).primaryColor),
)
: ElevatedButton(
onPressed: _login,
style: ElevatedButton.styleFrom(
primary: kWhiteCalm,
onPrimary: kDarkGreenColor,
onSurface: kGreyColor,
elevation: 5.0,
padding: EdgeInsets.all(5.0),
),
child: Text(
'LOGIN',
style: TextStyle(
color: Color(0xFF527DAA),
letterSpacing: 1.5,
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'OpenSans',
),
),
),
],
),
);
}
_login() {
final _form = _formKey.currentState;
if (_form.validate()) {
_form.save();
//print("Email $_email, Password $_password");
_LoginUser();
} else {
print("Form is Invalid");
}
}
_LoginUser() async {
setState(() {
_isSubmitting = true;
});
final logMessage =
await Provider.of<AuthenticationService>(context, listen: false)
.logIntoAccount(emailController.text, passwordController.text);
logMessage == "Signed In"
? _showSuccessSnack(logMessage)
: _showErrorSnack(logMessage);
//print("I am logMessage $logMessage");
if (logMessage == "Signed In") {
Navigator.pushReplacement(
context,
PageTransition(
child: HomeScreen(), type: PageTransitionType.bottomToTop));
} else {
setState(() {
_isSubmitting = false;
});
}
}
_showSuccessSnack(String message) async {
final snackbar = SnackBar(
backgroundColor: Colors.black,
content: Text(
"$message",
style: TextStyle(color: Colors.green),
),
);
ScaffoldMessenger.of(context).showSnackBar(snackbar);
_formKey.currentState.reset();
}
_showErrorSnack(String message) {
final snackbar = SnackBar(
backgroundColor: Colors.black,
content: Text(
"$message",
style: TextStyle(color: Colors.red),
),
);
ScaffoldMessenger.of(context).showSnackBar(snackbar);
setState(() {
_isSubmitting = false;
});
}
}

When the user trying to login, it doesn't stores their data in firestore, When I click Confirm location button it showing following error

class AuthProvider with ChangeNotifier {
FirebaseAuth _auth = FirebaseAuth.instance;
String smsOtp;
String verificationId;
String error ='';
UserServices _userServices = UserServices();
bool loading = false;
LocationProvider locationData = LocationProvider();
String screen;
double latitude;
double longitude;
String address;
Future<void> verifyPhone({BuildContext context, String number}) async {
this.loading=true;
notifyListeners();
final PhoneVerificationCompleted verificationCompleted =
(PhoneAuthCredential credential) async {
this.loading=false;
notifyListeners();
await _auth.signInWithCredential(credential);
};
final PhoneVerificationFailed verificationFailed =
(FirebaseAuthException e) {
this.loading=false;
print(e.code);
this.error=e.toString();
notifyListeners();
};
final PhoneCodeSent smsOtpSend = (String verId, int resendToken) async {
this.verificationId = verId;
};
//open dialog to enter received OTP sms
smsOtpDialog(context, number);
try {
_auth.verifyPhoneNumber(
phoneNumber: number,
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: smsOtpSend,
codeAutoRetrievalTimeout: (String verId){
this.verificationId = verId;
},
);
} catch (e) {
this.error=e.toString();
this.loading=false;
notifyListeners();
print(e);
}
}
Future<bool> smsOtpDialog(BuildContext context, String number) {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Column(
children: [
Text('Verification Code'),
SizedBox(height: 6,),
Text('Enter 6 digits OTP received via SMS',
style: TextStyle(color: Colors.grey,fontSize: 12),
),
],
),
content: Container(
height: 85,
child: TextField(
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
maxLength: 6,
onChanged: (value){
this.smsOtp = value;
},
),
),
actions: [
FlatButton(
onPressed: ()async{
try{
PhoneAuthCredential phoneAuthCredential =
PhoneAuthProvider.credential(
verificationId: verificationId, smsCode: smsOtp);
final User user = (await _auth.signInWithCredential(phoneAuthCredential)).user;
if(user!=null){
this.loading=false;
notifyListeners();
_userServices.getUserById(user.uid).then((snapShot){
if(snapShot.exists){
//user data already exists
if(this.screen=='Login'){
//need to check user data already exists in database or not
//if its login,no new data, so no need to update
Navigator.pushReplacementNamed(context, HomeScreen.id);
}else{
//need to update new selected address
print('${locationData.latitude} : ${locationData.longitude}');
updateUser(id: user.uid, number: user.phoneNumber);
Navigator.pushReplacementNamed(context, HomeScreen.id);
}
}else{
//user data doesn't exists
//will create new data in db
_createUser(id: user.uid, number: user.phoneNumber);
Navigator.pushReplacementNamed(context, HomeScreen.id);
}
});
}else
{
print('Login Failed');
}
} catch(e){
this.error = 'Invalid OTP';
notifyListeners();
print(e.toString());
Navigator.of(context).pop();
}
},
child: Text('SUBMIT',style: TextStyle(color: Theme.of(context).primaryColor),),
),
],
);
}).whenComplete(() {
this.loading=false;
notifyListeners();
});
}
void _createUser({String id, String number} ) {
_userServices.createUserData({
'id':id,
'number':number,
'latitude':this.latitude,
'longitude':this.longitude,
'address':this.address
});
this.loading=false;
notifyListeners();
}
Future <bool> updateUser({String id, String number,} ) async{
try{
_userServices.updateUserData({
'id':id,
'number':number,
'latitude':this.latitude,
'longitude':this.longitude,
'address':this.address
});
this.loading=false;
notifyListeners();
return true;
}catch(e){
print('Error $e');
return false;
}
}
}
======== Exception caught by gesture ===============================================================
The following NoSuchMethodError was thrown while handling a gesture:
The getter 'uid' was called on null.
Receiver: null
Tried calling: uid
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 _MapScreenState.build. (package:flutter_hasho_user/screens/map_screen.dart:146:44)
#2 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:993:19)
#3 _InkResponseState.build. (package:flutter/src/material/ink_well.dart:1111:38)
#4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:183:24)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#3d7f8
debugOwner: GestureDetector
state: possible
won arena
finalPosition: Offset(184.2, 647.6)
finalLocalPosition: Offset(164.2, 15.6)
button: 1
sent tap down
====================================================================================================
I am pretty sure your issue is calling .uid on a user in your else block when the user is null, which throws an error. You should make sure that the user class is initialized or something similar atleast.
else{
_createUser(id: user.uid, number: user.phoneNumber); // [user] is null
Navigator.pushReplacementNamed(context, HomeScreen.id);
}

Check if phone exists before signup/signin - Flutter Phone Authentication [duplicate]

This question already exists:
Firebase Authentication using Phone number (Error: Missing Session Info)
Closed 2 years ago.
I want to check if phone exists before signing in or signing up a user. With email registration, I used the following and I was able to tell if an email exists or not.
final url =
'https://www.googleapis.com/identitytoolkit/v3/relyingparty/$verifyPassword?key={API_KEY}';
Similarly, for phone numbers, I used the following:
final url ='https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPhoneNumber?key={API_KEY}';
final response = await http.post(
url,
body: json.encode(
{
'phoneNumber': number
},
),
);
However, I am getting the following error message:
Extracted data is {error: {code: 400, message: MISSING_SESSION_INFO, errors: [{message: MISSING_SESSION_INFO, domain: global, reason: invalid}]}}
I want to know why does it work for email but not for phone registration?
Also, is this the right way to check if a phone exists?
Here's my full code:
enum Status { Uninitialized, Authenticated, Authenticating, Unauthenticated }
class AuthProvider with ChangeNotifier {
FirebaseAuth _auth = FirebaseAuth.instance;
User _user;
Status _status = Status.Uninitialized;
TextEditingController phoneNo;
String smsOTP;
String verificationId;
String errorMessage = '';
bool logedIn = false;
bool loading = false;
Status get status => _status;
TextEditingController address = TextEditingController();
AuthProvider.initialize() {
readPrefs();
}
Future signOut() async {
_auth.signOut();
_status = Status.Unauthenticated;
notifyListeners();
return Future.delayed(Duration.zero);
}
Future<void> readPrefs() async {
await Future.delayed(Duration(seconds: 3)).then((v) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
logedIn = prefs.getBool('logedIn') ?? false;
if (!logedIn) {
print('User is not logged in');
_status = Status.Unauthenticated;
} else {
print('User is logged in');
_user = _auth.currentUser;
_status = Status.Authenticated;
}
notifyListeners();
});
}
Future<void> verifyPhone(BuildContext context, String number,String password) async {
//To be used in the verifyPhone method
final PhoneCodeSent smsOTPSent = (String verId, [int forceCodeResend]) {
this.verificationId = verId;
smsOTPDialog(context, number,password).then((value) {
_status = Status.Authenticated;
});
};
try {
await _auth.verifyPhoneNumber(
phoneNumber: number.trim(),
codeAutoRetrievalTimeout: (String verId) {
//Starts the phone number verification process for the given phone number.
//Either sends an SMS with a 6 digit code to the phone number specified, or sign's the user in and [verificationCompleted] is called.
this.verificationId = verId;
},
codeSent: smsOTPSent,
// timeout: const Duration(seconds: 20),
//If user is automatically verified (without having to type the code)
verificationCompleted: (AuthCredential credential) async {
Navigator.of(context).pop();
UserCredential result =
await _auth.signInWithCredential(credential);
User user = result.user;
if (user != null) {
//TO DO:// Here you need to save the phone and password to DB
print('Adding user to DB');
final url = 'https://mobile-12.firebaseio.com/users/$number.json';
try {
await http.post(
url,
body: json.encode({
'password': password,
'phoneNumber':user.phoneNumber,
}),
);
_status = Status.Authenticated;
} catch (error) {
print(error);
}
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(
)));
} else {
print("Error");
}
},
verificationFailed: (FirebaseAuthException exceptio) {
print('${exceptio.message} + something is wrong');
});
} catch (e) {
handleError(e, context,number,password);
errorMessage = e.toString();
notifyListeners();
}
notifyListeners();
}
Future<bool> smsOTPDialog(BuildContext context,String number,String password) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Enter SMS Code'),
content: Container(
height: 85,
child: Column(children: [
TextField(
onChanged: (value) {
this.smsOTP = value;
},
),
(errorMessage != ''
? Text(
errorMessage,
style: TextStyle(color: Colors.red),
)
: Container())
]),
),
contentPadding: EdgeInsets.all(10),
actions: <Widget>[
FlatButton(
child: Text("Confirm"),
textColor: Colors.white,
color: Colors.blue,
onPressed: () async {
final code = this.smsOTP.trim();
AuthCredential credential = PhoneAuthProvider.credential(
verificationId: verificationId, smsCode: code);
UserCredential result =
await _auth.signInWithCredential(credential);
User user = result.user;
if (user != null) {
print('user already exist');
// //TO DO:// Save the phone number and password to DB
print('Adding user to Db in the manual OTP route');
final url = 'https://mobile-12.firebaseio.com/users/$number.json';
try {
await http.post(
url,
body: json.encode({
'password': password,
'phoneNumber':user.phoneNumber,
}),
);
} catch (error) {
print('INSIDE ERROR');
print(error);
}
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("logedIn", true);
logedIn = true;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(
)));
loading = false;
notifyListeners();
} else {
print("No OTP was added");
loading = true;
notifyListeners();
Navigator.of(context).pop();
}
},
)
],
);
});
}
//Sign-In Method checks to see if a phone exists.
signIn(BuildContext context, String number, String password,AuthMode authMode) async {
try {
//Check to see if the phone number is available
final url = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPhoneNumber?key=';
final response = await http.post(
url,
body: json.encode(
{
'phoneNumber': number
},
),
);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
print('Extracted data is ' + extractedData.toString());
//Register and send OTP if new user
if (extractedData == null && authMode == AuthMode.Signup) {
print('Inside NULL no errors');
// //Verify phone
verifyPhone(context, number, password);
}
//If tries to login but phone not available
else if(extractedData == null && authMode == AuthMode.Login)
{
_showErrorDialog('Phone number does not exist. Please Sign Up', context);
}
else if (extractedData['error'] != null) {
_showErrorDialog('Something went wrong! Please try again!', context);
}
//If someone signup but their phone already exist
else if(extractedData != null && authMode == AuthMode.Signup)
{
_showErrorDialog('Your phone already exists. Please Login!', context);
}
//If available, proceed to homepage
else {
print('User found');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(
)));
}
} catch (e) {
handleError(e, context,number,password);
}
}
handleError(error, BuildContext context,String number,String password) {
errorMessage = error.toString();
print('ERROR IS ' + errorMessage);
notifyListeners();
}
Future<bool> _showErrorDialog(String message,BuildContext context) {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text('An Error Occurred!'),
content: Text(message),
actions: <Widget>[
FlatButton(
child: Text('Okay'),
onPressed: () {
Navigator.of(ctx).pop();
},
)
],
),
);
}
}

How to make register using email/password and send Code to the phone in Firebase

I want to allow users to register an account on my app using flutter with email/password, and then send code to the phone. So when user enters their data to Sign up, it should register them with their email and then use their phone to the verity code. Also the user can't complete the registration and go to the Home page Without checking the entered code.
But in my code it's not working what i want do it.
My click function:
dynamic ruselt= await _auth.regsiterwithemail(_emailcontroller.text,_passwordcontroller.text);
if (ruselt!=null){
setState(() async {
loading =false;
verfitycode().verfityphoen(context);
});
}else{
setState(() {
loading=false;
SweetAlert.show(context,
title: "Title",
style: SweetAlertStyle.confirm,
subtitle: "Subtitle");
});
}
My registration function:
Future regsiterwithemail(String email , String password )
async {
try{
AuthResult result =await _auth.createUserWithEmailAndPassword(email: email, password: password);
FirebaseUser user =result.user;
print('oky');
return _userfirebaseUser(user);
}catch(e){
print(e.toString());
return null;
}
}
class for verity code
class verfitycode {
String phonenumber;
String smsCode;
String vialdid;
GlobalKey<FormState>_form;
Future<void> verfityphoen(BuildContext context)async{
final PhoneCodeAutoRetrievalTimeout AutoRetriv =(String verid) {
this.vialdid =verid;
};
final PhoneCodeSent smsCodeset =(String verid,[int forceResendingToken]){
this.vialdid=verid;
smscodeDialog(context);
};
final PhoneVerificationCompleted verfiedcompletd=(AuthCredential user){
print('verfild');
};
final PhoneVerificationFailed verfilederror =(AuthException exception){
print('${exception.message}');
};
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber:"+967776523152",
timeout: const Duration(seconds:5),
verificationCompleted: verfiedcompletd,
verificationFailed: verfilederror,
codeSent: smsCodeset,
codeAutoRetrievalTimeout: AutoRetriv
);
}
Future<bool> smscodeDialog(BuildContext context){
Alert(
context: context,
title: "رمز التحقق",
content: Column(
children: <Widget>[
Form(
key: _form,
child: Directionality(
textDirection: TextDirection.rtl,
child:
TextField(
onChanged: (val){
this.smsCode=val;
},
decoration:InputDecoration (
icon: Icon(Icons.supervisor_account),
labelText: 'ادخل رمز التحقق',
),
),
)
)
],
),
buttons: [
DialogButton(
child: Text('خروج', style: TextStyle(color: Colors.white, fontSize:18)), onPressed:()=>Navigator.pop(context)),
DialogButton(
onPressed: (){
// _form.currentState.validate();
FirebaseAuth.instance.currentUser().then((user) {
if (user != null) {
Navigator.pop(context);
Navigator.push(context,
MaterialPageRoute(builder: (context) => Home()));
} else {
Navigator.pop(context);
_testSignlink();
}
});
},
child: Text(
"ادخل الرمز",
style: TextStyle(color: Colors.white, fontSize:18),
),
),
]).show();
}
_testSignlink() async {
FirebaseUser user;
String _smsCodeController;
final AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: vialdid,
smsCode: smsCode,
);
await user.linkWithCredential(credential).then((user){
print(user.user.uid);
}).catchError((onError){
print(onError.toString());
});
_smsCodeController = '';
return 'signInWithPhoneNumber succeeded: $user';
}
}

Resources