1
votes

Comment mettre à jour les données pour FirebaseUser Stream lorsque l'e-mail est vérifié (Flutter)

Je suis en train de créer une application Flutter avec l'authentification Firebase pour les utilisateurs. Mon objectif est de rationaliser l'expérience d'intégration des utilisateurs en permettant l'inscription et la vérification par e-mail sans forcer l'utilisateur à se déconnecter et à se reconnecter pour utiliser toutes les fonctionnalités. Avant de tester avec de vrais utilisateurs, c'est exactement ce que j'avais configuré, mais le retour écrasant est que cela interrompt et peut même amener l'utilisateur à abandonner complètement le flux d'authentification; l'application devrait simplement détecter ce changement d'état de vérification sans avoir à se déconnecter.

CE QUE J'AI ESSAYÉ

J'utilise ce qui suit dans main.dart pour fournir l'état d'authentification dans toute l'application:

StreamProvider < FirebaseUser > .value( value: FirebaseAuth.instance.onAuthStateChanged, ),

Je l'extrait avec user1 = Provider.of<FirebaseUser>(context, listen: true); dans les pages individuelles et accédez à différentes propriétés comme user1.isEmailVérifié dans des expressions ternaires pour déterminer ce qui est affiché à l'utilisateur.

Je sais que onAuthStateChanged n'est pas appelé pour des modifications dans la vérification des e-mails, uniquement pour la connexion et la déconnexion de l'utilisateur comme expliqué dans la réponse acceptée pour cette question , mais je dois toujours mettre à jour la valeur utilisateur qui détermine l'interface utilisateur affichée lorsqu'un utilisateur vérifie leur e-mail. J'ai choisi d'utiliser un bouton «vérification complète des e-mails» qui déclenchera manuellement la vérification et le rechargement du profil utilisateur avec la nouvelle valeur une fois vérifié. Voici le code de ce bouton:

() async {
    // 1
    FirebaseUser user =
    await _firebaseAuth.currentUser();
    print(user.isEmailVerified); // returns false
    // 2
    await user.getIdToken();
    print(user.isEmailVerified);// returns false
    // 3
    await user.reload();
    print(user.isEmailVerified);// returns false
    //4
    user = await _firebaseAuth.currentUser(); 
    print(user.isEmailVerified);// this finally returns true
}

où final _firebaseAuth = FirebaseAuth.instance;

J'ai remarqué qu'appeler .currentUser () deux fois (avant et après reload ()) est le seul moyen de renvoyer true pour la propriété .isEmailVerified sans se déconnecter et se reconnecter. C'est une réponse que j'ai trouvée dans ce fil GitHub .

Si j'appuie à nouveau sur le bouton, toutes les instructions d'impression ci-dessus retournent true.

LE PROBLÈME

C'est génial, mais le problème est que la variable user1 qui stocke le flux FirebaseUser ne change pas ou ne se met pas à jour même après cela, donc l'interface utilisateur reste la même malgré la vérification de l'e-mail de l'utilisateur. Je le sais car j'ai placé les vérifications suivantes dans le code:

print('this one is from the stream:'); print(user1.isEmailVerified);

Il renvoie toujours false même lorsque dans le corps de la fonction de bouton, l'utilisateur.isEmailVerified renvoie true.

J'ai essayé d'appeler set state dans le bouton comme ceci:

setState(() {user1 = user; });

Mais il semble que la valeur de user1 reste toujours la même et retourne toujours false pour user1.isEmailVerified, même si j'essaie de la définir sur la nouvelle valeur dérivée de la fonction du bouton!

C'est vraiment frustrant car je me sens très proche, mais je ne sais tout simplement pas comment actualiser la valeur de l'utilisateur1 (flux utilisateur Firebase) dans toute l'application ou même simplement sur cet écran. Cela devrait être plus simple.

J'ai remarqué que le fait d'appuyer sur le rechargement à chaud après avoir vérifié l'e-mail et sur le bouton ci-dessus affichera automatiquement la valeur .isEmailVerified mise à jour dans toute l'application lors du débogage lors du flutter. Existe-t-il un moyen de déclencher par programme le même type de reconstruction que celui utilisé par le rechargement à chaud, qui actualisera également les données du flux utilisateur Firebase SANS avoir à se déconnecter et à se reconnecter? C'est peut-être là que réside la réponse, mais je ne sais pas comment procéder.

Toute aide serait appréciée.


0 commentaires

3 Réponses :


0
votes

Le plugin FirebaseAuth Flutter fournit un Stream avec onAuthStateChanged, ce qui est utile pour obtenir des mises à jour lorsqu'un utilisateur se connecte ou se déconnecte, mais il ne parvient pas à fournir une mise à jour lorsque les données utilisateur elles-mêmes changent. Un problème courant est lorsque nous voulons détecter si l'utilisateur vient de vérifier son adresse e-mail, en d'autres termes obtenir si FirebaseUser.isEmailVerified a changé sa valeur, car elle est mise à jour côté serveur et non poussée vers l'application.

FirebaseAuth.currentUser () ne détectera que les modifications apportées localement à l'utilisateur, mais si des modifications sont apportées côté serveur, il ne détectera pas, à moins que FirebaseUser.reload () ne soit appelé en premier et que nous devions appeler FirebaseAuth.currentUser ( ) à nouveau pour obtenir l'utilisateur rechargé, mais cet utilisateur ne sera toujours pas émis par onAuthStateChanged.

Cela peut vous aider: https://pub.dev/packages/firebase_user_stream

Vous trouverez une solution manuelle ou vous pouvez utiliser le package.


0 commentaires

0
votes

Je suis tombé sur votre question en essayant de comprendre pourquoi user.reload () ne mettait pas à jour le statut de vérification des e-mails de mon utilisateur. Merci d'avoir suggéré de récupérer à nouveau currentUser, ce qui fonctionne.

Pour répondre à votre question, j'utilise un BehaviorSubject de rxdart pour stocker mon FirebaseUser, afin que je puisse recevoir des notifications de changement d'utilisateur de n'importe où dans l'application avec un StreamBuilder:

final BehaviorSubject<FirebaseUser> firebaseUser = new BehaviorSubject<FirebaseUser>();
userListener = FirebaseAuth.instance.onAuthStateChanged.listen((user) {

  if (user == null) {
    userSignedOut();
  }
  else if (currentFirebaseUser == null || user.uid != currentFirebaseUser.uid) {
    processNewUser(user);
  }
  firebaseUser.add(user);
});


0 commentaires

0
votes

L'écouteur de changement d'état d'authentification n'a pas fonctionné pour moi. Le champ isEmailVerified reste false même après que l'utilisateur a vérifié son e-mail.

Ma solution de contournement: à partir de l'hypothèse que l'utilisateur quitte l'application pour vérifier son courrier électronique (ce qui signifie que l'application est en pause ), et il revient à l'application après l'avoir vérifiée (l'application reprend ).

Ce que j'ai fait, c'est de joindre un WidgetsBinding à un widget avec état pertinent que je voulais afficher si l'e-mail était vérifié (mais peut être fait ailleurs). Cela implique deux étapes.

La première étape consiste à attacher la liaison:

  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed && !firebaseUser.isEmailVerified)
      refreshFirebaseUser().then((value) => setState(() {}));
    super.didChangeAppLifecycleState(state);
  }
  Future<void> refreshFirebaseUser() async {
    await firebaseUser.reload();
    firebaseUser = FirebaseAuth.instance.currentUser;
  }

La deuxième étape consiste à remplacer didChangeAppLifecycleState pour recharger l'utilisateur. J'ai créé une fonction qui fait le rechargement et définit un nouvel objet firebaseUser

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

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

Donc, ce que cela fait essentiellement est de recharger l'objet utilisateur Firebase à chaque fois que l'utilisateur revient dans l'application, alors que son e-mail n'est pas vérifié. Cela semble plus propre que la meilleure solution de contournement que j'ai trouvée dans SO qui consistait à définir et à annuler une action récurrente via une minuterie.


0 commentaires