Flutter bloc 和 Firebase 电话身份验证

Posted

技术标签:

【中文标题】Flutter bloc 和 Firebase 电话身份验证【英文标题】:Flutter bloc and Firebase phone auth 【发布时间】:2019-08-05 14:07:43 【问题描述】:

enter code here我正在尝试创建一个使用 Firebase 电话身份验证的 LoginBloc。我为phoneNumber、smsCode 和verificationId 创建了一个StreamController。我想借助 Bloc 模式在 VerificationNumber() 方法中动态添加它们的值。这是 verifyNumber() 中的 LoginBloc:

class LoginBloc extends Object with AuthValidator implements BlocBase 

  String _phone;
  String _sms;
  String _verifId;

  StreamController<String> _phoneController=StreamController<String>.broadcast();

  //Sink<String> get _addPhone=>_phoneController.sink;
  Stream<String> get getPhone=>_phoneController.stream.transform(validatePhone);

  StreamController<String> _codeController=StreamController<String>.broadcast();

  Stream<bool> get registerValid => Observable.combineLatest2(getPhone,getPhone
          ,(e, p) =>true);

  //Sink<String> get _addCode=>_phoneController.sink;
  Stream<String> get getCode=>_phoneController.stream.transform(validatePhone);
  Function(String) get onPhoneChanged => _phoneController.sink.add;

  StreamController<String> _verificationIdController=StreamController<String>.broadcast();

  Sink<String> get _addVerification=>_verificationIdController.sink;
  Stream<String> get getVerification=>_verificationIdController.stream;

  @override
  void dispose() 
    _phoneController.close();
    _codeController.close();
    _verificationIdController.close();
  

  Future<void> verifyPhone(String phone, String verifId,String sms) async 

    _phone=phone;
    _sms=sms;
    _verifId=verifId;

    final PhoneCodeAutoRetrievalTimeout autoRetrieve=(String verId) 
      _verifId=verId;
      _addVerification.add(_verifId);
    ;

    final PhoneCodeSent smsCodeSent=(String verId,[int forceCodeRetrieve]) 
      _verifId=verId;
      _addVerification.add(_verifId);
    ;

    final PhoneVerificationCompleted phoneVerificationCompleted=(FirebaseUser user) 
      print("User $user");
    ;

    final PhoneVerificationFailed phoneVerificationFailed=(AuthException exception) 
      print("Error $exception");
    ;

    await FirebaseAuth.instance.verifyPhoneNumber(
        phoneNumber: _phone,
        timeout: Duration(minutes: 1),
        verificationCompleted: phoneVerificationCompleted,
        verificationFailed: phoneVerificationFailed,
        codeSent: smsCodeSent,
        codeAutoRetrievalTimeout: autoRetrieve);
  


LoginBloc loginBloc=LoginBloc();

【问题讨论】:

【参考方案1】:

我现在有一个工作解决方案: 这是 login_bloc:

import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:phone_auth_bloc/services/auth/authentification.dart';
import 'package:rxdart/rxdart.dart';
import 'package:bloc_pattern/bloc_pattern.dart';

class LoginBloc implements BlocBase 
  final Authentification _authentification = new Authentification();


  final _phoneControler = new BehaviorSubject<String>();
  Observable<String> get phoneStream => _phoneControler.stream;
  Sink<String> get phoneEvent => _phoneControler.sink;

  final _smsControler = new BehaviorSubject<String>();
  Observable<String> get smsStream => _phoneControler.stream;
  Sink<String> get smsEvent => _phoneControler.sink;

  var _controllerLoading = new BehaviorSubject<bool>(seedValue: false);

  Stream<bool> get outLoading => _controllerLoading.stream;

  final BuildContext context;
  LoginBloc(this.context);

   onClickPhone() async 
    print(_phoneControler.value);
    _controllerLoading.add(!_controllerLoading.value);

        await _authentification.verifyPhoneNumber(_phoneControler.value);
    _controllerLoading.add(!_controllerLoading.value);


  

  Future<bool> onClickSms() async 
    print(_phoneControler.value);

    _controllerLoading.add(!_controllerLoading.value);
    bool isAuth = await _authentification.signWithPhone(
        _authentification?.verificationId, _smsControler.value);
    _controllerLoading.add(!_controllerLoading.value);
    print(isAuth);
    return isAuth;
  

  @override
  void dispose() 
    _controllerLoading?.close();
    _phoneControler?.close();
    _smsControler?.close();
  

和班级女巫交流:

class Authentification
  final _firebaseAuth= FirebaseAuth.instance;
   String verificationId;

  Future<bool> signWithPhone(String verifiId,String smsCode) async
    verificationId=verifiId;
    print(verificationId);
   final resultLogin=await _firebaseAuth.signInWithPhoneNumber(verificationId: verificationId, smsCode: smsCode);
   if(resultLogin?.uid!=null)
      return true;
   else
     return false;
   
  

  Future verifyPhoneNumber(String phone)async
    await _firebaseAuth.verifyPhoneNumber(
        phoneNumber: phone,
        timeout: Duration(seconds: 30),
        verificationCompleted: (FirebaseUser user)
          print("User: "+user?.uid);
        ,
        verificationFailed: (AuthException authException)
          print("exception: $authException");
        ,
        codeSent: (String verifId,[int forceSent])
          print("verificannId: $verifId");
          verificationId=verifId;
        ,
        codeAutoRetrievalTimeout: (String timeOut)
          print("Time out: "+timeOut);
        );
  

之后,您可以在 Ui 中调用 bloc,这是我的情况:

class AuthForm extends StatefulWidget 
  @override
  _AuthFormState createState() => _AuthFormState();


class _AuthFormState extends State<AuthForm> 
  @override
  Widget build(BuildContext context) 
    LoginBloc loginBloc = BlocProvider.of<LoginBloc>(context);

    navigateTOnext()
      loginBloc.onClickPhone().then((v)


          Navigator.of(context).pushReplacement(MaterialPageRoute(
              builder: (BuildContext context) =>SmsCode()
          ),);
       // else
         // Center(child: CircularProgressIndicator());
        //
      );

    

    return Scaffold(
      appBar: AppBar(
        title: Text("formulaire d'authentification"),
      ),
      body: Container(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              onChanged:loginBloc.phoneEvent.add,
              onSubmitted:(String value) =>loginBloc.onClickPhone,
              maxLength: 13,
              keyboardType: TextInputType.phone,
              decoration: InputDecoration(labelText: "Phone number"),
            ),
            RaisedButton(
              onPressed: navigateTOnext,

              child: Text("verifier"),
            ),
          ],
        ),
      ),
    );


  

【讨论】:

很好的例子。 ui 中的这一行 builder: (BuildContext context) =&gt;SmsCode() 不清楚。你能澄清一下 SmsCode() 方法在做什么吗? builder: (BuildContext context) =>SmsCode() 它只是一个等待短信发送到电话号码的另一个 UI 屏幕。

以上是关于Flutter bloc 和 Firebase 电话身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Stream/Bloc/Repository/Firebase 数据流 Flutter

使用 BLoC 进行 Flutter Firebase 电话身份验证

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

Flutter Bloc 与 firebase 查询有多种关系

具有多个firebase请求的flutter bloc cubit最佳实践

Flutter BLoC 架构 - 角色