Flutter 如何在登录页之后为小部件树中的所有小部件提供身份验证证书,并使导航器仍在工作

Flutter 如何在登录页之后为小部件树中的所有小部件提供身份验证证书,并使导航器仍在工作,flutter,dart,Flutter,Dart,我正在构建一个应用程序,我想在其中检查用户是否登录,如果没有,我将构建一个特定的小部件树。因此,如果用户的身份验证状态更改,它将重建整个树。因此,您登录到启动页面,启动页面等待,直到它知道您是否登录,然后返回RegisterPage或GroupManagementPage,这基本上是一个页面,您可以看到您的所有组,有点像whatsapp,但您没有组的对话。问题是我就是想不出如何正确地做到这一点 我正在使用firebase auth,目前我所做的是从主应用程序外部提供一个Authenticatio

我正在构建一个应用程序,我想在其中检查用户是否登录,如果没有,我将构建一个特定的小部件树。因此,如果用户的身份验证状态更改,它将重建整个树。因此,您登录到启动页面,启动页面等待,直到它知道您是否登录,然后返回RegisterPage或GroupManagementPage,这基本上是一个页面,您可以看到您的所有组,有点像whatsapp,但您没有组的对话。问题是我就是想不出如何正确地做到这一点

我正在使用firebase auth,目前我所做的是从主应用程序外部提供一个AuthenticationProvider。在我的启动页面中,我在流生成器中使用该提供者的流(基本上是从firebase更改的onAuthChanged,但映射到AuthenticationCertificate),我等待流处于活动状态,然后构建我的小部件树的其余部分。如果流处于活动状态,我将向GroupManagementPage提供我的AuthenticationCertificate

这是可行的,但导航器会出现问题。因为在我的MainApp()中,我将启动页面定义为我的主路径。所以现在,每当我弹出一条路线,我都会回到初始页面,这不是我想要的。我还注意到有些页面没有提供AuthenticationCertificate。我还不知道为什么,因为导航器也会传递上下文,所以仍然需要研究它

现在我的问题是,如何才能使其正常工作,以便将AuthenticationCertificate传递给从GroupManagementPage导航到的所有小部件,并且当用户注销时,它返回到RegisterPage?这是正确的方法吗?我如何才能做到这一点

主应用程序

return MultiProvider(
  providers: [
    ChangeNotifierProvider<PreferencesProvider>(
        create: (_) => PreferencesProvider()),
    Provider<AuthenticationProvider>(create: (_) => AuthenticationProvider(),),
    Provider<GroupProvider>(create: (_) => GroupProvider()),
    Provider<UserProvider>(
      create: (_) => UserProvider(),
    ),
  ],
  child: Consumer<PreferencesProvider>(
    builder: (context, preferences, _) => MaterialApp(
      home: TheSplashPage(),
      routes: <String, WidgetBuilder>{
        TheRegisterPage.routeName: (BuildContext context) =>
            TheRegisterPage(),
        TheGroupManagementPage.routeName: (BuildContext context) =>
            TheGroupManagementPage(),
        TheGroupPage.routeName: (BuildContext context) => TheGroupPage(),
        TheSettingsPage.routeName: (BuildContext context) =>
            TheSettingsPage(),
        TheProfilePage.routeName: (BuildContext context) =>
            TheProfilePage(),
        TheGroupCreationPage.routeName: (BuildContext context) =>
            TheGroupCreationPage(),
      },
      theme: preferences.isDarkMode
          ? DarkTheme.themeData
          : LightTheme.themeData,
      debugShowCheckedModeBanner: false,
    ),
  ),
);
返回多提供程序(
供应商:[
变更通知提供者(
创建:()=>PreferencesProvider()),
提供程序(创建:(\u)=>AuthenticationProvider(),),
提供程序(创建:(\u)=>GroupProvider()),
提供者(
创建:()=>UserProvider(),
),
],
儿童:消费者(
生成器:(上下文、首选项,)=>MaterialApp(
主页:splashpage(),
路线:{
TheRegisterPage.routeName:(构建上下文)=>
TheRegisterPage(),
GroupManagementPage.routeName:(构建上下文)=>
组管理页(),
TheGroupPage.routeName:(构建上下文)=>TheGroupPage(),
SettingsPage.routeName:(构建上下文)=>
设置间隔(),
TheProfilePage.routeName:(构建上下文)=>
profile页(),
GroupCreationPage.routeName:(构建上下文)=>
GroupCreationPage(),
},
主题:preferences.isDarkMode
?黑色主题
:LightTheme.motedata,
debugShowCheckedModeBanner:false,
),
),
);
启动页面

class TheSplashPage extends StatelessWidget {
  static const int loadTimeInSeconds = 2;

  @override
  Widget build(BuildContext context) {
    AuthenticationProvider authenticationProvider =
        Provider.of<AuthenticationProvider>(context);
    return FutureBuilder(
        future: Future.delayed(new Duration(seconds: loadTimeInSeconds)),
        builder: (context, delaySnapshot) {
          return StreamBuilder<UserAuthenticationCertificate>(
            stream: authenticationProvider.authenticationStream(),
            builder: (context, certificateSnapshot) {
              if (delaySnapshot.connectionState != ConnectionState.done &&
                  certificateSnapshot.connectionState ==
                      ConnectionState.active) {
                return Scaffold(
                  backgroundColor: Theme.of(context).backgroundColor,
                  body: Center(
                    child: Text(
                      'This is the splash page',
                      style: Theme.of(context).textTheme.body1,
                    ),
                  ),
                );
              } else {
                if (certificateSnapshot.hasData) {
                  return Provider<UserAuthenticationCertificate>.value(
                    value: certificateSnapshot.data, 
                    child: TheGroupManagementPage(),
                  );
                } else {
                  return TheRegisterPage();
                }
              }
            },
          );
        });
  }
}
class TheSplashPage扩展了无状态小部件{
静态常量int loadTimeInSeconds=2;
@凌驾
小部件构建(构建上下文){
AuthenticationProvider AuthenticationProvider=
(上下文)的提供者;
回归未来建设者(
future:future.delayed(新的持续时间(秒:loadTimeInSeconds)),
生成器:(上下文,延迟快照){
返回流生成器(
流:authenticationProvider.authenticationStream(),
生成器:(上下文、证书快照){
如果(delaySnapshot.connectionState!=connectionState.done&&
证书napshot.connectionState==
连接状态(活动){
返回脚手架(
背景色:主题。背景色,
正文:中(
子:文本(
“这是启动页面”,
样式:Theme.of(context).textTheme.body1,
),
),
);
}否则{
if(certificateSnapshot.hasData){
返回Provider.value(
值:certificateSnapshot.data,
子项:组管理页(),
);
}否则{
返回注册表页();
}
}
},
);
});
}
}
验证提供程序中的流

  Stream<UserAuthenticationCertificate> authenticationStream()
  {
    return _authentication.onAuthStateChanged.map((firebaseUser) => UserAuthenticationCertificate.fromFirebase(firebaseUser));
  }
streamauthenticationstream()
{
返回_authentication.onAuthStateChanged.map((firebaseUser)=>UserAuthenticationCertificate.fromFirebase(firebaseUser));
}
如果要使用流,请使用而不是提供程序。但我不知道你为什么要在这种情况下使用Stream。为什么不更改通知提供者

使用
Navigator.of(context)
导航到您的页面。代码的导航部分很奇怪。在splashpage()的生成函数中返回GroupManagementPage()或RegisterPage()。这不是Navigator的工作方式。您应该使用导航器的方法,如
push
pop
pushNamed

  Navigator.of(context).pushNamed(TheGroupManagementPage.routeName);
所以现在,每当我弹出一条路线,我都会回到初始页面,这不是我想要的

登录后,您可以从导航树中删除SplashPage。这是一种方法,也是一种不错的方法。在验证后推送页面时,应使用
pushReplacement
pushreplacementname
。您还可以将其用于注销,用RegisterPage()替换导航器树


或者,如果您有一个主屏幕,如启动后的根路径,那么在您的情况下,这可能是GroupManagement页面。然后将群组管理页面包装在一个WillPopScope中,并在willpop上执行您将在其中执行的操作。不过我更喜欢第一种方法。

我选择使用流,因为onAuth