Flutter中Firebase UID校验及路由跳转异常问题排查
问题描述
我想在main.dart中校验Firebase用户的登录状态:已登录则直接跳转至HomeScreen并传入UID,未登录则跳转至SignIn页面。但最初的代码出现黑屏(调试打印语句正常),改成用StreamBuilder实现后,又出现错误提示“Navigator operation requested with a context that does not include a Navigator”,错误关联组件是StreamBuilder<User?>。
第一段(初始代码)
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(MyApp()); } //User logged in? final FirebaseAuth auth = FirebaseAuth.instance; final User? user = auth.currentUser; class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { FirebaseAuth.instance.authStateChanges().listen((User? user) { if (user == null) { print('User is currently signed out!'); MaterialPageRoute(builder: (context) => const SignIn()); } else { String myUid = user.uid; MaterialPageRoute(builder: (context) => HomeScreen(userId: myUid)); print('User is signed in!'); } }); return const SizedBox.shrink(); //<-----here } }
第二段(修改后代码)
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(MyApp()); } //User logged in? final FirebaseAuth auth = FirebaseAuth.instance; //The stream for auth changee Future<User?> data() async { return FirebaseAuth.instance.currentUser; } final User? user = auth.currentUser; class MyApp extends StatelessWidget { MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return StreamBuilder<User?>( stream: FirebaseAuth.instance .authStateChanges(), //FirebaseAuth.instance.authStateChanges(), builder: (context, snapshot) { if (snapshot.hasError) { return const Text('Something went wrong'); } if (snapshot.connectionState == ConnectionState.waiting) { return const Text("Loading"); } if (snapshot.connectionState == ConnectionState.active) { if (user == null) { print('User is currently signed out!'); Navigator.push(context, MaterialPageRoute(builder: (context) => const SignIn())); } else { String myUid = user!.uid; Navigator.push( context, MaterialPageRoute( builder: (context) => HomeScreen( userId: myUid, ))); } } return const CircularProgressIndicator(); }); } }
问题原因与解决方法
初始代码黑屏原因
初始代码中MyApp的build方法返回了const SizedBox.shrink(),这是一个不可见的空组件,导致界面黑屏。同时你仅创建了MaterialPageRoute对象,未调用Navigator执行跳转,所以即使打印正常,页面也不会切换。
修改后代码的Navigator错误原因
在StreamBuilder的builder中直接调用Navigator.push时,当前context未包含Navigator——因为MyApp直接返回StreamBuilder,而Navigator必须嵌套在MaterialApp(或CupertinoApp)内部才能生效,缺少导航上下文自然无法执行导航操作。
正确实现方式
核心思路:以MaterialApp作为根组件,在MaterialApp的home中通过StreamBuilder根据用户登录状态返回对应页面,无需手动调用Navigator.push。
示例代码:
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Firebase Auth Demo', debugShowCheckedModeBanner: false, home: StreamBuilder<User?>( stream: FirebaseAuth.instance.authStateChanges(), builder: (context, snapshot) { // 加载状态显示加载指示器 if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // 错误状态提示 if (snapshot.hasError) { return const Center(child: Text('登录状态校验出错')); } // 根据用户状态返回对应页面 final User? user = snapshot.data; if (user == null) { // 未登录返回SignIn页面 return const SignIn(); } else { // 已登录返回HomeScreen并传入UID return HomeScreen(userId: user.uid); } }, ), ); } }
额外注意点
- 不要在
build方法外提前获取currentUser,因为初始化阶段currentUser可能还未完成异步校验,直接获取会得到null,而authStateChanges()流会实时推送最新用户状态。 MaterialApp是Flutter导航的基础,所有需要使用Navigator的页面必须嵌套在MaterialApp(或CupertinoApp)内部。
内容的提问来源于stack exchange,提问作者M.Nasiri
相关产品推荐
相关产品推荐

