简体   繁体   中英

How to use Flutter Bloc with Firebase Phone Auth

I'm trying to implement Firebase phone authorization using Flutter Bloc pattern. I have the following code

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);
        });
  }
}

But i can't use yield inside verifyPhoneNumber callbacks. The question is how to yield different states inside of callback functions?

You can add an event from your callback. For example, in verificationCompleted , you can do:

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

And you can handle the AuthCompleted() event on mapEventToState :

@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
    }
  }

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())));
                }
              }}

UI Screen

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,
        );
      }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM