如何将 Flutter Bloc 与 Firebase 电话身份验证一起使用

Posted

技术标签:

【中文标题】如何将 Flutter Bloc 与 Firebase 电话身份验证一起使用【英文标题】:How to use Flutter Bloc with Firebase Phone Auth 【发布时间】:2020-04-26 02:23:20 【问题描述】:

我正在尝试使用 Flutter Bloc 模式实现 Firebase 电话授权。 我有以下代码

import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:firebase_auth/firebase_auth.dart';
import './bloc.dart';

class AuthBloc extends Bloc<AuthEvent, AuthState> 
  final FirebaseAuth _auth = FirebaseAuth.instance;

  @override
  AuthState get initialState => AuthNotStarted();

  @override
  Stream<AuthState> mapEventToState(
    AuthEvent event,
  ) async* 
    if (event is VerifyPhone) 
      yield* _mapVerifyPhoneToState(event);
    
  

  Stream<AuthState> _mapVerifyPhoneToState(VerifyPhone event) async* 
    yield AuthStarted();
    _auth.verifyPhoneNumber(
        phoneNumber: "+" + event.phoneNumber,
        timeout: Duration(seconds: 60),
        verificationCompleted: (AuthCredential authCredential) 
          print("verification completed: auth credential");
        ,
        verificationFailed: (AuthException authException) 
          print("verification failed: auth exception");
          print(authException.message);
        ,
        codeSent: (String verificationId, [int forceResendingToken]) 
          print("code sent verification id" + verificationId);
        ,
        codeAutoRetrievalTimeout: (String verificationId) 
          print("auto time" + verificationId);
        );
  

但我不能在 verifyPhoneNumber 回调中使用 yield。 问题是如何在回调函数内部产生不同的状态?

【问题讨论】:

【参考方案1】:

您可以从回调中添加事件。比如在verificationCompleted,你可以这样做:

verificationCompleted: (AuthCredential authCredential) 
    print("verification completed: auth credential");
    add(AuthCompleted());
,

您可以在mapEventToState 上处理AuthCompleted() 事件:

@override
  Stream<AuthState> mapEventToState(
    AuthEvent event,
  ) async* 
    if (event is VerifyPhone) 
      yield* _mapVerifyPhoneToState(event);
    
    if (event is AuthCompleted)
      //Here you can use yield and whathever you want
    
  

【讨论】:

【参考方案2】:

PhoneAuthenticationBloc

class PhoneAuthenticationBloc
        extends Bloc<PhoneAuthenticationEvent, PhoneAuthenticationState> 
      final AuthRepository _authRepository;
      final AuthBloc _authBloc;      
        
           
            @override
          Stream<PhoneAuthenticationState> mapEventToState(
            PhoneAuthenticationEvent event,
          ) async* 
            if (event is PhoneLoadingEvent) 
              yield PhoneLoadingState();
             else if (event is PhoneVerificationFailedEvent) 
              yield PhoneOTPFailureState(event.failure);
             else if (event is PhoneSmsCodeSentEvent) 
              yield PhoneSmsCodeSentState(
                  verificationId: event.verificationId, resendCode: event.resendId);
             else if (event is PhoneVerifiedOtpEvent) 
              yield* _mapToVerifyOtp(event.smsCode, event.verificationId);
            
          
             void verifyPhoneNumber(String phoneNumber) async 
                try 
                  add(PhoneLoadingEvent());
                  await _authRepository.verifyPhoneNumber(phoneNumber,
                      onRetrieval: (String retrievalCode) 
                    print("Time Out Retrieval Code: $retrievalCode");
                  , onFailed: (Failure f) 
                    print("OnFailed: $f.message");
            
                    add(PhoneVerificationFailedEvent(f));
                  , onCompleted: (Map<String, dynamic> data) 
                    print("verificationCompleted: $data");
                  , onCodeSent: (String verificationId, int resendCode) 
                    print("verificationId:$verificationId & resendCode: $resendCode");
                    add(PhoneSmsCodeSentEvent(
                        verificationId: verificationId, resendId: resendCode));
                  );
                 catch (e) 
                  add(PhoneVerificationFailedEvent(Failure(message: e.toString())));
                
              

用户界面屏幕

builder: (context, state) 
        return AppButton(
          isLoading: state is PhoneLoadingState,
          onPressed: () async 
            if (_formKey.currentState.validate()) 
              BlocProvider.of<PhoneAuthenticationBloc>(context)
                  .verifyPhoneNumber(_phoneController.text);
            
          ,
          title: "Continue",
          textColor: Colors.white,
        );
      

【讨论】:

以上是关于如何将 Flutter Bloc 与 Firebase 电话身份验证一起使用的主要内容,如果未能解决你的问题,请参考以下文章

将flutter_bloc与tabview一起使用

Flutter BLoC - 如何将参数传递给事件?

Flutter,如何将exist Bloc用于其他屏幕?

如何使用flutter_bloc处理动画

flutter - bloc - 我如何在我的 Ui 中使用 FutureBuilder 来正确实现 Bloc 架构

如何在BLOC的Flutter中设置BottomNavigationBar中的currentIndex?