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

Flutter中GoRouter+SharedPreferences认证流程context.goNamed失效问题

GoRouter + SharedPreferences 认证跳转失效问题解决

问题描述

我尝试用GoRouter和SharedPreferences实现Flutter认证流程:用户未登录时自动跳转至LoginScreen,已登录则跳转至MainLayout。但目前SplashScreen中的context.goNamed方法完全无法生效,控制台也没有输出任何报错信息。

SplashScreen核心逻辑代码

@override
void initState() {
  super.initState();

  WidgetsBinding.instance.addPostFrameCallback((_) {
    checkLoginState();
  });
}

void checkLoginState() {
  print("in");
  if (locator.get<AppPreferences>().isLoggedIn()) {
    print("in questMainLayoutRoute");
    context.goNamed(AppRouteName.questMainLayoutRoute);
  } else {
    print("in loginScreen");
    context.goNamed(AppRouteName.loginScreen);
  }
}

@override
void dispose() {
  super.dispose();
}

路由配置代码

abstract class AppRoute {
  static GoRouter routes = GoRouter(
    redirect: (context, state) => AppRouteName.splashScreen,
    routes: [
      GoRoute(
        name: AppRouteName.splashScreen,
        path: AppRouteName.splashScreen,
        builder: (context, state) => SplashScreen(),
      ),
     
      GoRoute(
        name: AppRouteName.loginScreen,
        path: AppRouteName.loginScreen,
        builder: (context, state) => LoginUI(),
      ),
      GoRoute(
        name: AppRouteName.questMainLayoutRoute,
        path: AppRouteName.questMainLayoutRoute,
        builder: (context, state) => QuestMainLayout(),
      ),
    ]
  );
}

问题根源

你的GoRouter全局redirect配置强制所有路由请求都跳转到SplashScreen,导致SplashScreen内的跳转刚触发,就被全局redirect拉回启动页,所以视觉上完全没变化,也不会报错。

修复方案

方案1:修正全局redirect逻辑

只在用户未处于SplashScreen时才跳转启动页,避免循环拦截:

abstract class AppRoute {
  static GoRouter routes = GoRouter(
    redirect: (context, state) {
      // 检查当前是否已经在启动页
      final isOnSplash = state.location == AppRouteName.splashScreen;
      // 只有不在启动页时,才跳转过去做登录检查
      return isOnSplash ? null : AppRouteName.splashScreen;
    },
    routes: [
      // 原有路由配置保持不变
      GoRoute(
        name: AppRouteName.splashScreen,
        path: AppRouteName.splashScreen,
        builder: (context, state) => SplashScreen(),
      ),
      GoRoute(
        name: AppRouteName.loginScreen,
        path: AppRouteName.loginScreen,
        builder: (context, state) => LoginUI(),
      ),
      GoRoute(
        name: AppRouteName.questMainLayoutRoute,
        path: AppRouteName.questMainLayoutRoute,
        builder: (context, state) => QuestMainLayout(),
      ),
    ],
  );
}

方案2:优化登录状态检查(避免同步读取SharedPreferences的坑)

SharedPreferences的读取本质是异步操作,同步读取可能拿到旧值或空值,建议修改为异步实现:

  1. 更新AppPreferences的isLoggedIn方法:
Future<bool> isLoggedIn() async {
  final prefs = await SharedPreferences.getInstance();
  return prefs.getBool('is_logged_in') ?? false;
}
  1. 对应修改SplashScreen的checkLoginState:
void checkLoginState() async {
  print("in");
  final isLoggedIn = await locator.get<AppPreferences>().isLoggedIn();
  // 确保页面未销毁时再调用context
  if (!mounted) return;
  
  if (isLoggedIn) {
    print("in questMainLayoutRoute");
    context.goNamed(AppRouteName.questMainLayoutRoute);
  } else {
    print("in loginScreen");
    context.goNamed(AppRouteName.loginScreen);
  }
}

方案3:直接在全局redirect中处理登录逻辑(更简洁)

如果不需要SplashScreen做过渡,可以把登录检查直接放到全局redirect里,省去启动页的跳转逻辑:

abstract class AppRoute {
  static GoRouter routes = GoRouter(
    redirect: (context, state) async {
      final isLoggedIn = await locator.get<AppPreferences>().isLoggedIn();
      final currentPath = state.location;
      
      // 未登录且不在登录页 → 跳登录
      if (!isLoggedIn && currentPath != AppRouteName.loginScreen) {
        return AppRouteName.loginScreen;
      }
      // 已登录且不在主页面 → 跳主页面
      if (isLoggedIn && currentPath != AppRouteName.questMainLayoutRoute) {
        return AppRouteName.questMainLayoutRoute;
      }
      // 其他情况不做跳转
      return null;
    },
    routes: [
      GoRoute(
        name: AppRouteName.loginScreen,
        path: AppRouteName.loginScreen,
        builder: (context, state) => LoginUI(),
      ),
      GoRoute(
        name: AppRouteName.questMainLayoutRoute,
        path: AppRouteName.questMainLayoutRoute,
        builder: (context, state) => QuestMainLayout(),
      ),
    ],
  );
}

内容的提问来源于stack exchange,提问作者soufiane ben yaala

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:14:53