Flutter 如何在登录页之后为小部件树中的所有小部件提供身份验证证书,并使导航器仍在工作
我正在构建一个应用程序,我想在其中检查用户是否登录,如果没有,我将构建一个特定的小部件树。因此,如果用户的身份验证状态更改,它将重建整个树。因此,您登录到启动页面,启动页面等待,直到它知道您是否登录,然后返回RegisterPage或GroupManagementPage,这基本上是一个页面,您可以看到您的所有组,有点像whatsapp,但您没有组的对话。问题是我就是想不出如何正确地做到这一点 我正在使用firebase auth,目前我所做的是从主应用程序外部提供一个AuthenticationProvider。在我的启动页面中,我在流生成器中使用该提供者的流(基本上是从firebase更改的onAuthChanged,但映射到AuthenticationCertificate),我等待流处于活动状态,然后构建我的小部件树的其余部分。如果流处于活动状态,我将向GroupManagementPage提供我的AuthenticationCertificate 这是可行的,但导航器会出现问题。因为在我的MainApp()中,我将启动页面定义为我的主路径。所以现在,每当我弹出一条路线,我都会回到初始页面,这不是我想要的。我还注意到有些页面没有提供AuthenticationCertificate。我还不知道为什么,因为导航器也会传递上下文,所以仍然需要研究它 现在我的问题是,如何才能使其正常工作,以便将AuthenticationCertificate传递给从GroupManagementPage导航到的所有小部件,并且当用户注销时,它返回到RegisterPage?这是正确的方法吗?我如何才能做到这一点 主应用程序Flutter 如何在登录页之后为小部件树中的所有小部件提供身份验证证书,并使导航器仍在工作,flutter,dart,Flutter,Dart,我正在构建一个应用程序,我想在其中检查用户是否登录,如果没有,我将构建一个特定的小部件树。因此,如果用户的身份验证状态更改,它将重建整个树。因此,您登录到启动页面,启动页面等待,直到它知道您是否登录,然后返回RegisterPage或GroupManagementPage,这基本上是一个页面,您可以看到您的所有组,有点像whatsapp,但您没有组的对话。问题是我就是想不出如何正确地做到这一点 我正在使用firebase auth,目前我所做的是从主应用程序外部提供一个Authenticatio
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