有时Provider在flutter中匿名注册后不会触发

Posted

技术标签:

【中文标题】有时Provider在flutter中匿名注册后不会触发【英文标题】:Sometimes Provider doesn't trigger after anonymous sign-up in flutter 【发布时间】:2021-09-25 14:18:56 【问题描述】:

你好 Flutter 开发者,

我在使用 Flutter 开发自己的应用程序时遇到了一个错误,这让我的生活变得非常复杂。它是这样的:

    用户打开应用 如果他们没有登录,他们会被重定向到 USP 页面。 如果他们点击下一步,他们将被重定向到注册页面。 注册由 Firebase 提供,并且是匿名的 如果注册成功,应触发Provider 并加载新页面

错误是有时用户会被送回 USP 页面(意味着他们的user_idnull),尽管在注册期间没有抛出异常。如果我强制导航到登录页面,则用户没有user_id,这对我来说是个问题。

任何人遇到并解决了同样的问题?下面你可以看到我是如何构建我的代码的,也许这会有所帮助?

这是我的主文件:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

Future<void> main() async 
  WidgetsFlutterBinding.ensureInitialized();
  await SignIn.initializeFirebase();
  runApp(MyApp());


class MyApp extends StatelessWidget 

  getSignInUser() 
    return SignIn().user;
  

  Widget getMaterialApp() 
    return MaterialApp(
      title: 'app_title',
      home: HomePagePicker(),
      onGenerateRoute: RouteGenerator.generateRoute,
      debugShowCheckedModeBanner: false,
    );
  

  @override
  Widget build(BuildContext context) 
    return MultiProvider(
      providers: [
        StreamProvider<MyUser?>.value(value: SignIn().user, initialData: null),
      ],
      child: getMaterialApp(),
    );
  




class HomePagePicker extends StatefulWidget 

  @override
  _HomePagePickerState createState() => _HomePagePickerState();


class _HomePagePickerState extends State<HomePagePicker> 

  @override
  Widget build(BuildContext context) 
    MyUser? myUser = Provider.of<MyUser?>(context);

    if (myUser == null) return IntroScreen(); // this shows the USPs
    else  
     // this takes you to the signed-in part of the app
      return AnotherScreen();
    
  

IntroScreen 是一个非常简单的屏幕,带有几个 USP 和一个用于打开注册页面的按钮。它类似于

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'login.dart';

class IntroScreen extends StatelessWidget 
  static const routeName = '/introScreen';

  @override
  Widget build(BuildContext context) 
    analytics.setScreenName("introScreen");
    return Scaffold(
        body: AnnotatedRegion<SystemUiOverlayStyle>(
            value: SystemUiOverlayStyle(statusBarColor: ThemeConfig.darkPrimary),
            child: Column(...), // show the USPs
        floatingActionButton: getFloatingButton(context)
    );

  

  Widget getFloatingButton(BuildContext buildContext) 
    return FloatingActionButton(
      backgroundColor: ThemeConfig.primary,
      foregroundColor: Colors.white,
      child: Icon(Icons.arrow_forward),
      onPressed: () 
        navigateToScreen(MyLogin.routeName, buildContext, null);
      ,
    );
  

  // this is in another file normally but putting it here for completeness
  navigateToScreen(String routeName, BuildContext context, Object? arguments) 
    Navigator.pushNamed(
        context,
        routeName,
        arguments: arguments
    );



注册页面的重点是这个

Future<void> finalizeRegistration(String userName, String userToken) async 
    await usersCollection.add('userName': userName, "userToken": userToken);
  

Future<void> registerUser(String userName) 
    return SignIn()
        .anonymousSignIn(userName)
        .timeout(Duration(seconds: 2))
        .then((userToken) 
          finalizeRegistration(userName, userToken)
              .then((value) => Navigator.pop(context));
        )
        .catchError((error) 
          registrationErrorDialog();
        );
  

SignIn 类如下

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:house_party/models/MyUser.dart';

class SignIn 
  final FirebaseAuth _auth = FirebaseAuth.instance;

  static Future<FirebaseApp> initializeFirebase() async 
    FirebaseApp firebaseApp = await Firebase.initializeApp();
    return firebaseApp;
  

  Stream<MyUser?> get user 
    return _auth
        .authStateChanges()
        .asyncMap(getUser);
  

  Future<String> anonymousSignIn(String userName) async 
    var authResult = await _auth.signInAnonymously();
    return authResult.user!.uid;
  


  Future<MyUser?> getUser(User? user) async 
    if (user == null) 
      return Future.value(null);
    
    return FirebaseFirestore.instance
        .collection('users')
        .where('userToken', isEqualTo: user.uid)
        .get()
        .then((res) 
          if (res.docs.isNotEmpty) 
            return MyUser.fromFireStore(res.docs.first.data());
           else 
            return null;
          
    );
  



最后,我正在使用这些版本的 firebase

  firebase_core: ^1.0.0
  cloud_firestore: ^1.0.0
  firebase_dynamic_links: ^2.0.0
  firebase_auth: 1.1.2
  firebase_analytics: ^8.1.1

我希望问题陈述足够清楚!

提前致谢!

【问题讨论】:

【参考方案1】:

我通过如下升级firebase库解决了这个问题(或者至少我不能再重现它了)

  firebase_core: ^1.4.0
  cloud_firestore: ^2.4.0
  firebase_dynamic_links: ^2.0.7
  firebase_auth: 3.0.1
  firebase_analytics: ^8.2.0

【讨论】:

以上是关于有时Provider在flutter中匿名注册后不会触发的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:如何设置 Stream 和 Provider

Flutter Provider:Firebase Auth StateChanges 被监听但状态没有改变

自定义状态管理Provider以及原理分析

自定义状态管理Provider以及原理分析

补丁/更新后不与提供者更新状态,颤振

WebServiceHost在IIS中禁用匿名身份验证后不起作用