Stuck returning verificationId from Future<String> method Flutter
258
Finally managed to use it properly from Bloc.
Methods are:
UserRepository
Future<void> verifyPhone(
{@required String phoneNumber,
@required Duration timeOut,
@required PhoneVerificationFailed phoneVerificationFailed,
@required PhoneVerificationCompleted phoneVerificationCompleted,
@required PhoneCodeSent phoneCodeSent,
@required PhoneCodeAutoRetrievalTimeout autoRetrievalTimeout}) async {
_firebaseAuth.verifyPhoneNumber(
phoneNumber: phoneNumber,
timeout: timeOut,
verificationCompleted: phoneVerificationCompleted,
verificationFailed: phoneVerificationFailed,
codeSent: phoneCodeSent,
codeAutoRetrievalTimeout: autoRetrievalTimeout);
}
Future<AuthResult> verifyAndLinkAuthCredentials(
{@required String verificationId, @required String smsCode}) async {
AuthCredential authCredential = PhoneAuthProvider.getCredential(
verificationId: verificationId, smsCode: smsCode);
// return _firebaseAuth.signInWithCredential(authCredential);
FirebaseUser user = await _firebaseAuth.currentUser();
return user.linkWithCredential(authCredential).catchError((e) {
print('UserRepository.verifyAndLinkAuthCredentials() error: $e');
// return;
});
}
Callbacks are defined in bloc Streams:
@override
Stream<AuthenticationState> mapEventToState(
AuthenticationEvent event) async* {
// phone verification
if (event is VerifyPhoneNumberEvent) {
print('VerifyPhoneNumberEvent received');
yield VerifyingState();
yield* _mapVerifyPhoneNumberToState(event);
}
if (event is PhoneCodeSentEvent) {
print('PhoneCodeSentEvent received');
yield OtpSentState();
}
if (event is VerificationCompletedEvent) {
print('VerificationCompletedEvent received');
yield VerificationCompleteState(firebaseUser: event.firebaseUser, isVerified: event.isVerified);
}
if (event is VerificationExceptionEvent) {
print('VerificationExceptionEvent received');
yield VerificationExceptionState(message: event.message);
}
if ( event is PhoneCodeAutoRetrievalTimeoutEvent){
yield PhoneCodeAutoRetrievalTimeoutState(verificationId: event.verificationId);
}
if(event is SendVerificationCodeEvent) {
yield VerifyingState();
yield*_mapVerificationCodeToState(event);
}
}
Stream<AuthenticationState> _mapVerifyPhoneNumberToState(VerifyPhoneNumberEvent event) async* {
print('_mapVerifyPhoneNumberToState V2 started');
final phoneVerificationCompleted = (AuthCredential authCredential) {
print('_mapVerifyPhoneNumberToState PhoneVerificationCompleted');
_userRepository.getCurrentUser().catchError((onError) {
print(onError);
}).then((user) {
add(VerificationCompletedEvent(firebaseUser: user, isVerified: true));
});
};
final phoneVerificationFailed = (AuthException authException) {
print('_mapVerifyPhoneNumberToState PhoneVerificationFailed');
print(authException.message);
add(VerificationExceptionEvent(onError.toString()));
};
final phoneCodeSent = (String verificationId, [int forceResent]) {
print('_mapVerifyPhoneNumberToState PhoneCodeSent');
this.verificationId = verificationId;
add(PhoneCodeSentEvent());
};
final phoneCodeAutoRetrievalTimeout = (String verificationId) {
print('_mapVerifyPhoneNumberToState PhoneCodeAutoRetrievalTimeout');
this.verificationId = verificationId;
add(PhoneCodeAutoRetrievalTimeoutEvent(verificationId: verificationId));
};
await _userRepository.verifyPhone(
phoneNumber: event.phoneNumber,
timeOut: Duration(seconds: 0),
phoneVerificationFailed: phoneVerificationFailed,
phoneVerificationCompleted: phoneVerificationCompleted,
phoneCodeSent: phoneCodeSent,
autoRetrievalTimeout: phoneCodeAutoRetrievalTimeout);
}
Stream<AuthenticationState> _mapVerificationCodeToState(SendVerificationCodeEvent event) async* {
print('_mapVerificationCodeToState started');
AuthResult result = await _userRepository.verifyAndLinkAuthCredentials(verificationId: verificationId, smsCode: event.smsCode)
.catchError((e){
print('verifyAndLinkAuthCredentials error: $e');
});
print(result);
if (result != null) {
yield VerificationCompleteState(firebaseUser: result.user, isVerified: true);
} else {
yield OtpExceptionState(message: "Invalid otp!", verificationId: verificationId);
}
}
Hope this helps others. Cheers.
Author by
Vincenzo
Updated on December 25, 2022Comments
-
Vincenzo over 1 year
I'm trying to authenticate user with phone and as I'm using flutter_bloc and Repository the approach I'm having is:
- Send event with phone number to Bloc(OK).
- Call
verifyPhoneNumber
passing in the phone number (OK). - Return the
verificationId
received from eithercodeAutoRetrievalTimeout
orcodeSent
callbacks. - Send it to UI from
BlocListener
with a State. - Update UI to enter the verification code.
- Send smsCode and verificationId to another method to link phone AuthCredential to user.
My method returns before callbacks are called as verifyPhoneNumber completes first so it's returning a null String.
What I'm doing wrong? As always many thanks for your help.
Future<String> verifyPhoneNumber(String phoneNumber) async { print('verifyPhoneNumber() started'); String verifyId; await _firebaseAuth .verifyPhoneNumber( phoneNumber: phoneNumber, timeout: Duration(minutes: 0), //error: Undefined class 'PhoneAuthCredential'. // verificationCompleted: (PhoneAuthCredential credential) async { verificationCompleted: (AuthCredential credential) { }, //error: Undefined class 'FirebaseAuthException'. // verificationFailed: (FirebaseAuthException e) { verificationFailed: (AuthException e) { if (e.code == 'invalid-phone-number') { print( 'verifyPhoneNumber() -> verificationFailed -> The provided phone number is not valid.'); } else { print( 'verifyPhoneNumber() -> verificationFailed :${e.message}'); } // Handle other errors }, codeAutoRetrievalTimeout: (String verificationId) { // Auto-resolution timed out... // verifyId = verificationId; print( 'verifyPhoneNumber() -> codeAutoRetrievalTimeout callback called'); }, //error: The argument type 'Null Function(String, int)' can't be assigned to the parameter type 'void Function(String, [int])'. // codeSent: (String verificationId, int resendToken) { codeSent: (String verificationId, [int resendToken]) { verifyId = verificationId; print( 'verifyPhoneNumber() -> codeSent callback called : $verifyId'); // correct return verifyId; } ) .then((value) { print('verifyId is $verifyId'); // null // return verifyId; }).whenComplete(() => print('Complete')); print('verifyPhoneNumber() ->returning verifyId: $verifyId'); return verifyId; // without it method doesn't return, with it returns null }