I'm trying to implement phone authentication in my Flutter application using FirebaseAuth.instance.verifyPhoneNumber but do not know how to await it in an async function, so that the asynchronous codeSent parameter completes before moving on.
For example, with the following code:
ElevatedButton(
onPressed: () async {
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: phoneNumber,
verificationCompleted: (phoneAuthCredential) {},
verificationFailed: (error) {},
codeSent: (verificationId, forceResendingToken) async {
await Future.delayed(
Duration(seconds: 2),
);
},
codeAutoRetrievalTimeout: (verificationId) {},
);
print('COMPLETED');
},
child: Text('Verify'),
),
I want the Future.delayed(Duration(seconds: 2)) to complete before the print statement. Is there any way of implementing this functionality? Am I missing something obvious?
If all you want is for Future.delayed(Duration(seconds: 2)) to be completed before the print statement, then call the print statement inside the codeSent method. Like this
codeSent: (String verificationId, [int? forceResendingToken]) async {
await Future.delayed(const Duration(seconds: 2));
print('COMPLETED');
},
Related
i'm would like to add a button for existing user to verify phone number on their profile page,
Future<void> phoneVerification(String _mobile) async {
await _auth.verifyPhoneNumber(
phoneNumber: _mobile,
verificationCompleted: (PhoneAuthCredential phoneAuthCredential) async {
await userInfo.linkWithCredential(phoneAuthCredential);
},
verificationFailed: (FirebaseAuthException e) async {
// Handle error
print(e);
},
codeSent: (String verificationId, int resendToken) async {
},
codeAutoRetrievalTimeout: (String verificationId) async {
},
);
}
however nothing happened even i entered the OTP, verificationCompleted is not called
FlatButton(
onPressed: () async {
setState(() {
PhoneAuthCredential phoneAuthCredential = PhoneAuthProvider.credential(verificationId: verificationId, smsCode: OTP);
});
},
child: Text("VERIFY"),
color: Colors.blue,
textColor: Colors.white,
),
im having trouble with authentication on Firebase.
there is a login screen that asks for the number, then on the next button press it goes to the OTP screen that results in authenticating the user.
But after the verification number is typed, it doesnt authenticate and says Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
this is the code that i use to verify the user
final String PhoneNumber; //globally declared
_verifyPhone() async {
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: widget.PhoneNumber,
verificationCompleted: (PhoneAuthCredential credential) async {
await FirebaseAuth.instance
.signInWithCredential(credential)
.then((value) async {
if (value.user != null) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
EmailScreen(PhoneNumber: widget.PhoneNumber),
),
);
}
});
},
verificationFailed: (FirebaseAuthException e) {
print(e.message);
},
codeSent: (String verificationID, int resendToken) {
setState(() {
_verificationCode = verificationID;
});
},
codeAutoRetrievalTimeout: (String verificationID) {
setState(() {
_verificationCode = verificationID;
});
},
timeout: Duration(seconds: 60));
}
and this is the OnSubmit function of the PinEntryTextField
PinEntryTextField(
fields: 6,
showFieldAsBox: true,
onSubmit: (String pin) async {
try {
await FirebaseAuth.instance
.signInWithCredential(PhoneAuthProvider.credential(
verificationId: _verificationCode, smsCode: pin))
.then((value) async {
if (value.user != null) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EmailScreen(
PhoneNumber: widget.PhoneNumber,
)));
}
});
} catch (e) {
FocusScope.of(context).unfocus();
print(e);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text("Failed because $e"),
));
}
},
),
Now it works sometimes, but sometimes it doesn't, that's the weird thing.
any help would be appreciated..
thanks
Never mind, i had to wait a few seconds until the SMS code "arrives"..
Because i was using a test phone number
Silly me 😂😂
Please verify if the phone number is not going to be null. In my case phone number is going null so this error was come.
I am using Firebase_auth package for verifying phone number, Firebase send code but when I check the validity of code it just show error. when I print code sent it is different with the code that I receive. any one know please help me.
thanks in advance.
here is my code:
await FirebaseAuth.instance.verifyPhoneNumber(
timeout: Duration(seconds: 60),
phoneNumber: phoneNumber,
verificationCompleted:
(PhoneAuthCredential phoneAuthCredential) {
print(phoneAuthCredential.smsCode);
print("complete");
},
verificationFailed: (e) {
print("failed");
print(e);
},
codeSent: (same, a) {
print(a);
print(same);
Navigator.of(context).pushNamed(
VerifyScreen.routName,
arguments: {
'code': a,
'customerId': customerId,
},
);
},
codeAutoRetrievalTimeout: (sa) {
print(sa);
print("timeout");
},
);
I know the code received cannot be printed, but it comes in encrypted form verificationId.
When the entered code is verified, you send the code that was entered by the user and the verificationId to Firebase to verify it.
If your goal is to be verified automatically without entering the code through this verificationCompleted, you can transfer the user automatically.
Note: Provided that the sim card is on the same phone to which the code was sent.
Additional information: If you want the process to be automatic, use the following code:
Future singInPhoneNumber() async {
FirebaseAuth _auth = FirebaseAuth.instance;
_auth.verifyPhoneNumber(
phoneNumber: phoneNumber,
timeout: Duration(seconds: 60),
verificationCompleted: (AuthCredential phoneAuthCredential) async {
//Automatically verify
Navigator.of(context).pushNamed(
VerifyScreen.routName,
arguments: {
'code': a,
'customerId': customerId,
},
);
debugPrint("Firebase Auth :Auto Verification Completed");
},
verificationFailed: (FirebaseAuthException error) {
debugPrint("ERROR Firebase Auth : AuthException : ${error.message}");
showToast(context, 'Something went wrong, please try again later');
},
codeSent: (String verificationId, [int forceResendingToken]) {
setState(() {
this.verificationId = verificationId;
});
},
codeAutoRetrievalTimeout: (String verificationId) {
return null;
},
);
}
If you only want to enter the code manually:
AuthCredential credential = PhoneAuthProvider.credential(
verificationId: verificationId, smsCode: codeController.text);
_auth
.signInWithCredential(credential)
.then((value) => {
print('The operation completed successfully')
})
.catchError((onError) {
print(onError.toString());
});
I am trying to conduct a phone number login by sending sms code to my phone device using firebase auth. But the await keyword does not seem to work here. Why? my assumption is when I assign await to a function, Flutter prints the null value of the verificationId variable, verificationId gets its value within the _sendCodeToPhoneNumber function. Hence this could mean the function _sendCodeToPhoneNumber hasn't finished yet but the its next line of code (print(verificationId) in this case) is already executed. But if I am mistaken, then what is the problem? and more important, please teach me how to resolve problem? Because I have to get verificationId's value and pass it to the next class.
String verificationId;
Future<void> _sendCodeToPhoneNumber() async {
...
final PhoneCodeSent codeSent = (String verificationId, [int forceResendingToken]) async {
this.verificationId = verificationId; //this.verificationId here is not null because it has got a value
print('Code sent to ${_phoneNumberController.text} with $verificationId');
};
...
await FirebaseAuth.instance.verifyPhoneNumber(
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout,
phoneNumber: _phoneNumberController.text,
codeSent: codeSent,
timeout: const Duration(seconds: 120),
verificationCompleted: verificationCompleted,
verificationFailed: vericationFailed
);
}
...
FlatButton(onPressed: (){
await _sendCodeToPhoneNumber();
print(verificationId); // printed null despite having assigned `await` to the _sendCodeToPhoneNumber function
...
})
Change the function to the following and return the verificationId:
Future<String> _sendCodeToPhoneNumber() async {
final PhoneCodeSent codeSent = (String verificationId, [int forceResendingToken]) async {
this.verificationId = verificationId; //this.verificationId here is not null because it has got a value
print('Code sent to ${_phoneNumberController.text} with $verificationId');
};
await FirebaseAuth.instance.verifyPhoneNumber(
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout,
phoneNumber: _phoneNumberController.text,
codeSent: codeSent,
timeout: const Duration(seconds: 120),
verificationCompleted: verificationCompleted,
verificationFailed: vericationFailed
);
return this.verificationId;
}
Also change the onPressed, when using await you need to use async:
FlatButton(onPressed: (()async{
var result = await _sendCodeToPhoneNumber();
print(result);
}))
final PhoneCodeSent codeSent = (String verificationId, [int forceResendingToken]) async {
this.verificationId = verificationId; //this.verificationId here is not null because it has got a value
print('Code sent to ${_phoneNumberController.text} with $verificationId');
};
i think you dont need async here
I am looking for a way to resend the OTP in firebase verifyPhoneNumber in flutter.
I have gone through the example about phoneAuth but could not find a way to resend OTP.
There is an option of forceResendingToken
final PhoneCodeSent codeSent =
(String verificationId, [int forceResendingToken]) async {
this.verificationId = verificationId;
_smsCodeController.text = testSmsCode;
};
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: this._phone,
codeAutoRetrievalTimeout: autoRetrieval,
codeSent: smsCodeSent,
forceResendingToken: ,//how to get this token
timeout: const Duration(seconds: 40),
verificationCompleted: verifSuccessful,
verificationFailed: verifFailed);
}
How to use this token to resend the OTP.
From the Firebase reference documentation:
the ForceResendingToken obtained from onCodeSent(String, PhoneAuthProvider.ForceResendingToken) callback to force re-sending another verification SMS before the auto-retrieval timeout.
So in your case that'd be the PhoneCodeSent callback of the verifyPhoneNumber() call.
You have to record the value of resendToken from the codesent callback and pass it to the forceresendingtoken. Also, the inbuilt timeout duration is 30 seconds So make sure you tap on resend button after timeout seconds, you may use timerbutton package it's very handy in this case.
Firebase sends 3x same SMS code and then change it to different.
String _verificationId = "";
int? _resendToken;
Future<bool> sendOTP({required String phone}) async {
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: phone,
verificationCompleted: (PhoneAuthCredential credential) {},
verificationFailed: (FirebaseAuthException e) {},
codeSent: (String verificationId, int? resendToken) async {
_verificationId = verificationId;
_resendToken = resendToken;
},
timeout: const Duration(seconds: 25),
forceResendingToken: _resendToken,
codeAutoRetrievalTimeout: (String verificationId) {
verificationId = _verificationId;
},
);
debugPrint("_verificationId: $_verificationId");
return true;
}