卡住从 Future<String> 方法 Flutter 返回 verificationId
Stuck returning verificationId from Future<String> method Flutter
我正在尝试使用 phone 对用户进行身份验证,因为我正在使用 flutter_bloc 和存储库,所以我采用的方法是:
- 将编号为 phone 的事件发送到 Bloc(OK)。
- 呼叫
verifyPhoneNumber
传递 phone 号码(确定)。
- Return
verificationId
从 codeAutoRetrievalTimeout
或 codeSent
回调中收到。
- 从
BlocListener
以状态发送到 UI。
- 更新UI输入验证码
- 将 smsCode 和 verificationId 发送到另一个方法 link phone AuthCredential 给用户。
我的方法 returns 在调用回调之前,因为 verifyPhoneNumber 首先完成,所以它返回一个空字符串。
我做错了什么?
一如既往,非常感谢您的帮助。
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
}
终于设法从 Bloc 正确使用它了。
方法是:
用户存储库
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;
});
}
回调在 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);
}
}
希望这对其他人有帮助。
干杯。
我正在尝试使用 phone 对用户进行身份验证,因为我正在使用 flutter_bloc 和存储库,所以我采用的方法是:
- 将编号为 phone 的事件发送到 Bloc(OK)。
- 呼叫
verifyPhoneNumber
传递 phone 号码(确定)。 - Return
verificationId
从codeAutoRetrievalTimeout
或codeSent
回调中收到。 - 从
BlocListener
以状态发送到 UI。 - 更新UI输入验证码
- 将 smsCode 和 verificationId 发送到另一个方法 link phone AuthCredential 给用户。
我的方法 returns 在调用回调之前,因为 verifyPhoneNumber 首先完成,所以它返回一个空字符串。
我做错了什么? 一如既往,非常感谢您的帮助。
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
}
终于设法从 Bloc 正确使用它了。
方法是:
用户存储库
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;
});
}
回调在 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);
}
}
希望这对其他人有帮助。 干杯。