You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 01:33:24