Flutter启动页自动登录异常:始终跳转至登录页面求助
Flutter启动页自动登录逻辑问题排查
核心问题分析
1. 登录凭证硬编码,未使用SharedPreferences存储的值
你的signInWithEmailAndPassword方法里直接传了字符串字面量'email'和'password',而非从SharedPreferences获取的实际凭证,这会导致每次都用无效信息登录,必然触发错误分支。
2. 异步操作未等待,导致获取的凭证无效
sharedPrefInit()是异步方法,调用时未加await,可能SharedPreferences还没完成初始化就去获取凭证,导致拿不到正确值getCred('email')和getCred('password')返回的是Future<String>,你直接把Future对象赋值给变量,未用await获取实际字符串值,打印的$email其实是Future实例的描述,不是真实邮箱
3. catchError逻辑完全错误
signInWithEmailAndPassword登录成功时会走then回调,不会进入catchError。你把登录成功后的跳转逻辑放在catchError里的errMsg == null分支,这永远不会触发——因为只有登录失败时才会进入catchError,此时errMsg必然不为null,所以每次都会走到else分支跳转到登录页。
4. SharedPreferences类的细节问题
reset()方法内部有await操作,但返回值是void,应改为Future<void>,否则调用时无法等待清除操作完成getCred()方法中,如果prefs.getString(key)为null,toString()会得到字符串"null",这会导致用"null"作为邮箱/密码去登录,需要处理null场景
修正后的代码
启动页initState修正
@override void initState() { super.initState(); Timer(const Duration(seconds: 3), () async { // 等待SharedPreferences初始化完成 await sharedPreference().sharedPrefInit(); // 等待获取实际的邮箱和密码 String? email = await sharedPreference().getCred('email'); String? password = await sharedPreference().getCred('password'); print('Email: $email\nPassword $password'); // 先判断凭证是否为空,避免无效登录请求 if (email == null || password == null || email.isEmpty || password.isEmpty) { await sharedPreference().reset(); _navigateToLogin(); return; } try { // 使用获取到的凭证登录 await firebaseAuth.signInWithEmailAndPassword(email: email, password: password); // 登录成功,跳转首页 Navigator.pushAndRemoveUntil( context, PageRouteBuilder( transitionDuration: const Duration(seconds: 1), transitionsBuilder: (context, animation, animationTime, child) { animation = CurvedAnimation( parent: animation, curve: Curves.fastLinearToSlowEaseIn); return ScaleTransition( scale: animation, alignment: Alignment.center, child: child, ); }, pageBuilder: (context, animation, animationTime) { return HomeScreen(email: email); }, ), (route) => false, ); } catch (errMsg) { // 登录失败,重置SharedPreferences并跳转登录页 print('登录失败: $errMsg'); await sharedPreference().reset(); _navigateToLogin(); } }); } // 抽离跳转登录页逻辑,避免重复代码 void _navigateToLogin() { Navigator.pushReplacement( context, PageRouteBuilder( transitionDuration: const Duration(seconds: 1), transitionsBuilder: (context, animation, animationTime, child) { animation = CurvedAnimation( parent: animation, curve: Curves.fastLinearToSlowEaseIn); return ScaleTransition( scale: animation, alignment: Alignment.center, child: child, ); }, pageBuilder: (context, animation, animationTime) { return const LoginOrSignUp(); }, ), ); }
SharedPreferences类修正
import 'package:shared_preferences/shared_preferences.dart'; class sharedPreference { Future<void> sharedPrefInit() async { try { final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.getString("recipedia"); } catch (err) { SharedPreferences.setMockInitialValues({}); final SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString("recipedia", "my-app"); } } Future<void> saveCred({required String email, required String password}) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setString("email", email); await prefs.setString("password", password); } Future<String?> getCred(String key) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); // 直接返回null,避免将null转为"null"字符串 return prefs.getString(key); } // 修改返回值为Future<void>,支持await等待清除完成 Future<void> reset() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.clear(); } }
额外建议
- 不要每次都创建
sharedPreference()实例,可以在类中定义单例,避免重复初始化 - 可去掉启动页的固定3秒等待,改为等待初始化和登录请求完成后立即跳转,提升用户体验
内容的提问来源于stack exchange,提问作者Mr Fin
相关产品推荐
相关产品推荐

