Flutter中基于auto_router实现用户登录状态持久化的方案咨询
解决方案:结合AutoRouter与Bloc实现持久化登录状态
针对你遇到的问题,以下是更高效且符合Clean Architecture的实现方式,核心是修复AutoRouterGuard的逻辑,并优化状态监听流程:
1. 修复AuthGuard:监听Bloc状态变化,处理异步认证
之前的Guard仅同步获取一次AuthCubit状态,但appStarted()通常是异步操作(比如从本地存储读取token),需要在Guard中监听状态变化,直到认证状态确定:
class AuthGuard extends AutoRouteGuard { @override void onNavigation(NavigationResolver resolver, StackRouter router) { final authCubit = resolver.context.read<AuthCubit>(); final currentState = authCubit.state; // 处理已确定的状态 if (currentState is Authenticated) { resolver.next(true); } else if (currentState is Unauthenticated) { // 未认证时跳转到登录页,登录后可返回原导航意图 router.push(const SignInRoute()).then((_) { if (authCubit.state is Authenticated) { resolver.next(true); } else { resolver.next(false); } }); } else { // 初始加载状态下,监听状态变化后再处理 final subscription = authCubit.stream.listen((state) { subscription.cancel(); if (state is Authenticated) { resolver.next(true); } else { router.push(const SignInRoute()).then((_) { if (authCubit.state is Authenticated) { resolver.next(true); } else { resolver.next(false); } }); } }); } } }
2. 路由配置:为需要认证的页面添加Guard
在AutoRouter的路由配置中,给需登录才能访问的页面绑定AuthGuard:
@MaterialAutoRouter( replaceInRouteName: 'Page,Route', routes: [ AutoRoute(path: '/', page: SplashScreen), AutoRoute(path: '/sign-in', page: SignInPage), // 主页面及子路由添加认证守卫 AutoRoute( path: '/main', page: MainScreen, guards: [AuthGuard()], children: [ // 主页面的子路由配置 ], ), ], ) class $AppRouter {}
3. 优化App初始化流程:配合SplashScreen等待认证完成
以SplashScreen作为初始页面,通过BlocListener监听认证状态完成后再跳转,避免页面闪烁:
return MultiBlocProvider( providers: [ BlocProvider(create: (_) => di.sl<AuthCubit>()..appStarted()), BlocProvider(create: (_) => di.sl<CredentialCubit>()), BlocProvider(create: (_) => di.sl<UserCubit>()), BlocProvider(create: (_) => di.sl<GetSingleUserCubit>()), BlocProvider(create: (_) => di.sl<GetSingleOtherUserCubit>()), ], child: BlocListener<AuthCubit, AuthState>( listener: (context, state) { final router = AutoRouter.of(context); // 仅在状态从加载态变为确定态时跳转,避免重复触发 if (state is Authenticated) { router.replace(MainRoute(uid: state.uid)); } else if (state is Unauthenticated) { router.replace(const SignInRoute()); } }, child: MaterialApp.router( debugShowCheckedModeBanner: false, title: "Instagram Clone", darkTheme: ThemeData.dark(), routerDelegate: AutoRouterDelegate(AppRouter()), routeInformationParser: AppRouter().defaultRouteParser(), ), ), );
4. 关键注意事项
- 避免直接用sl获取Bloc:在Guard中通过
resolver.context.read<AuthCubit>()获取实例,确保与Widget树中的Bloc状态一致。 - 异步初始化处理:
appStarted()需正确从本地存储(如SharedPreferences、Hive)读取认证信息,更新AuthCubit状态。 - 跳转逻辑去重:BlocListener中仅处理状态从加载态切换到已认证/未认证的场景,防止重复跳转。
内容的提问来源于stack exchange,提问作者M.Hassan
相关产品推荐
相关产品推荐

