颤振:如何倾听FirebaseUser的电子邮件?

颤振:如何倾听FirebaseUser的电子邮件?,firebase,flutter,dart,firebase-authentication,state-management,Firebase,Flutter,Dart,Firebase Authentication,State Management,我的想法: 我想在flatter中使用Firebase Auth插件来注册用户。 但在他们可以访问应用程序之前,他们必须验证自己的电子邮件地址。 因此,我将注册后的Firebase用户推送到验证屏幕。这只是一个加载屏幕,告诉用户他必须验证他的电子邮件 但是现在:如果用户的电子邮件经过验证与否,我如何持续收听,并将其发送到主屏幕(如果是真的) 我是个新手,不知道是否需要使用Streams、Observables、while循环、setState()或其他方法来进行布尔检查。我也不知道如何设置解决方

我的想法: 我想在flatter中使用Firebase Auth插件来注册用户。 但在他们可以访问应用程序之前,他们必须验证自己的电子邮件地址。 因此,我将注册后的Firebase用户推送到验证屏幕。这只是一个加载屏幕,告诉用户他必须验证他的电子邮件

但是现在:如果用户的电子邮件经过验证与否,我如何持续收听,并将其发送到主屏幕(如果是真的)

我是个新手,不知道是否需要使用Streams、Observables、while循环、setState()或其他方法来进行布尔检查。我也不知道如何设置解决方案

这是我注册用户的基本代码:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';

class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  final Firestore _db = Firestore.instance;

  Future<FirebaseUser> get getUser => _auth.currentUser();

  Stream<FirebaseUser> get user => _auth.onAuthStateChanged;

  Future<FirebaseUser> edubslogin(String email, String password) async {
    try {
      final FirebaseUser user = await _auth.createUserWithEmailAndPassword(
        email: email,
        password: password,
      );
     
      await user.sendEmailVerification();
      
      //email verification somewhere here
    
      updateUserData(user);
      return user;
    } catch (error) {
      print(error);
      return null;
    }
  }
但是我没有从
isEmailVerified
中得到布尔值
true


我该怎么办?

此验证并不像您希望的那样简单。首先,存在识别用户已验证其电子邮件的问题。第二个问题是,没有任何类型的通知可以自动触发应用程序中的更改

检查此线程以获取有关emailVerified的信息:

我只能在以下情况下验证用户:1)创建了他们的帐户,2)让他们登录,3)然后检查以确保他们验证了他们的电子邮件

final FirebaseAuth _auth = FirebaseAuth.instance;

var _authenticatedUser = await _auth.signInWithEmailAndPassword(email: _email, password: _password); 

//where _email and _password were simply what the user typed in the textfields.



if (_authenticatedUser.isEmailVerified) {
        //Verified
      } else {
        //Not verified
        }

第2部分:如何让应用程序识别用户已确认其电子邮件?找到一种方法来触发检查确认的函数。一个按钮就足够容易了。如果您想让它显示“自动”,那么我想您可以创建一个计时器,每隔10秒左右检查电子邮件验证。

我找到了一种方法,更新firebase用户配置文件并在
init()中调用它,如下面的函数所示

void _checkEmailVerification() async {
    await widget.auth.getCurrentUser().then((user) {
      UserUpdateInfo userUpdateInfo = new UserUpdateInfo();
      userUpdateInfo.displayName = user.displayName;
      user.updateProfile(userUpdateInfo).then((onValue) {
        setState(() {
          _isEmailVerified = user.isEmailVerified;
        });
      });
    });
  }

我只是在我的应用程序中遇到了同样的情况。我的解决方案是在策略路由的initState方法中创建一个周期计时器,在验证电子邮件之前保持应用程序。它没有使用监听器那么优雅,但效果很好

bool _isUserEmailVerified;
Timer _timer;

@override
void initState() {
    super.initState();
    // ... any code here ...
    Future(() async {
        _timer = Timer.periodic(Duration(seconds: 5), (timer) async {
            await FirebaseAuth.instance.currentUser()..reload();
            var user = await FirebaseAuth.instance.currentUser();
            if (user.isEmailVerified) {
                setState((){
                    _isUserEmailVerified = user.isEmailVerified;
                });
                timer.cancel();
            }
        });
    });
}

@override
void dispose() {
    super.dispose();
    if (_timer != null) {
        _timer.cancel();
    }
}

我创建了一个流来处理这个问题。不是很优雅,但很管用。使用StreamProvider.value()来处理事件

  Stream<userVerificationStatus> checkUserVerified() async* {
    bool verified = false;
    yield userVerificationStatus(status: Status.LOADING); 
    while (!verified) {
      await Future.delayed(Duration(seconds: 5));
      FirebaseUser user = await _auth.currentUser();
      if(user!=null)await user.reload();
      if (user == null) {
        yield userVerificationStatus(status: Status.NULL);
      } else {
        print("isemailverified ${user.isEmailVerified}");
        await user.reload();
        verified = user.isEmailVerified;
        if(verified)
        yield userVerificationStatus(status: Status.VERIFIED);
        else
        yield userVerificationStatus(status: Status.NOT_VERIFIED);
      }
    }
  }
流checkUserVerified()异步*{
bool-verified=false;
产生userVerificationStatus(状态:status.LOADING);
而(!已验证){
等待未来。延迟(持续时间(秒:5));
FirebaseUser=等待_auth.currentUser();
如果(user!=null)等待user.reload();
if(user==null){
产生userVerificationStatus(状态:status.NULL);
}否则{
打印(“isemailverified${user.isemailverified}”);
等待user.reload();
已验证=user.isEmailVerified;
如果(已验证)
生成userVerificationStatus(状态:status.VERIFIED);
其他的
生成userVerificationStatus(状态:status.NOT\u VERIFIED);
}
}
}

由于authOnChanged
只侦听登录和注销操作,因此在您的登录方法中,首先注销,然后尝试登录

await _firebaseAuth.signOut();

authResult = await _firebaseAuth.signInWithEmailAndPassword(email: email, password: password);

return authResult.user;
onAuthChanged
中,当您控制用户.isEmailVerified时,它将在您注销后工作,即使您尚未登录,它也会更新用户,因为即使您尚未登录,注销也会触发您的
onAuthChanged


这就像作弊,但我发现的唯一没有超时的方法是这样。

为了让应用程序识别用户是否验证了他们的电子邮件,你可以通过一个简单的用户来实现。重新加载

为了亲自测试,请使用按下的代码执行一个按钮:

 FlatButton(
    child: Text("check"),
    textColor: Colors.white,
    onPressed: () async {
    try {
      FirebaseUser user = await _firebaseAuth.currentUser();
      await user.reload();
      user = await _firebaseAuth.currentUser();
        print( user.isEmailVerified); 
        

     } catch (e) {
      return e.message;
    }
}),

身份验证状态更改侦听器对我无效。即使用户验证了他的电子邮件,字段
isEmailVerified
仍然保持
false

我的解决方法: 假设用户离开应用程序以验证其电子邮件(这意味着应用程序已暂停),并在验证后返回应用程序(应用程序恢复)

我所做的是将一个
WidgetsBinding
附加到一个相关的有状态小部件上,在那里我想显示电子邮件是否经过验证(但可以在其他地方完成)。这包括两个步骤

第一步是附加绑定:

@覆盖
void initState(){
WidgetsBinding.instance.addObserver(这个);
super.initState();
}
@凌驾
无效处置(){
WidgetsBinding.instance.removeObserver(此);
super.dispose();
}
第二步是重写
didChangeAppLifecycleState
以重新加载用户。我创建了一个函数来重新加载并设置一个新的firebaseUser对象

void didchangeappifecyclestate(AppLifecycleState状态){
if(state==AppLifecycleState.resume&&!firebaseUser.isEmailVerified)
refreshFirebaseUser()。然后((值)=>setState((){}));
super.didChangeAppLifecycleState(州);
}
Future refreshFirebaseUser()异步{
等待firebaseUser.reload();
firebaseUser=FirebaseAuth.instance.currentUser;
}

因此,这基本上是在用户每次返回应用程序时重新加载firebase用户对象,而其电子邮件未经验证。我选择了这个解决方案,而不是设置和取消计时器,因为它避免了通过计时器设置重复操作,这对于这个特定的问题来说可能是过度的。

正确。如果用户验证其电子邮件,FirebaseAuth
idTokenChanges()
authStateChanges()
userChanges()
都不会向您发送事件。我正在使用多种方法在我的应用程序中获得电子邮件验证更新,它似乎运行良好

首先,我在initState()方法中检查状态,如果电子邮件未被验证,则启动计时器

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);

    //Get Authenticated user
    user = context.read<AuthenticationService>().currentUser();
    _isEmailVerified = user.emailVerified;
    if (!_isEmailVerified) _startEmailVerificationTimer();

    }
这是_startEmailVerificationTimer()方法

我的Firebase用户方法,以防任何人感兴趣:

  User currentUser() {
    return _firebaseAuth.currentUser;
  }

  User reloadCurrentUser() {
    User oldUser = _firebaseAuth.currentUser;
    oldUser.reload();
    User newUser = _firebaseAuth.currentUser;
    return newUser;
  }

我对firebase auth的最新版本也有同样的问题

但是我发现
 @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      user = context.read<AuthenticationService>().reloadCurrentUser();
      if (user.emailVerified) {
        setState(() {
          _isEmailVerified = user.emailVerified;
        });
        timer?.cancel();
      } else {
        if (!timer.isActive) _startEmailVerificationTimer();
      }
    } 
  }
 _startEmailVerificationTimer() {
    timer = Timer.periodic(Duration(seconds: 5), (Timer _) {
      user = context.read<AuthenticationService>().reloadCurrentUser();
      if (user.emailVerified) {
        setState(() {
          _isEmailVerified = user.emailVerified;
        });
        timer.cancel();
      }
    });
  }
  @override
  void dispose() {
    timer?.cancel();
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
  User currentUser() {
    return _firebaseAuth.currentUser;
  }

  User reloadCurrentUser() {
    User oldUser = _firebaseAuth.currentUser;
    oldUser.reload();
    User newUser = _firebaseAuth.currentUser;
    return newUser;
  }