Flutter+Firebase手机号/邮箱登录注册:空值检查运算符报错
Flutter Firebase 登录流程空指针问题修复
问题场景
实现基于手机号+邮箱的登录/注册流程:用户输入手机号获取OTP,若手机号已关联邮箱则跳登录页输邮箱密码;未关联则跳注册页绑定邮箱密码后进入应用。测试手机号已关联邮箱,但运行代码时报错:
Null check operator used on a null value
原代码
import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:thrifty/auth/auth_page.dart'; import '../screens/bottom_navigation_bar.dart'; import '../screens/home.dart'; import 'phone_verification.dart'; class WhichScreen extends StatefulWidget { const WhichScreen({super.key}); @override State<WhichScreen> createState() => _WhichScreenState(); } class _WhichScreenState extends State<WhichScreen> { @override Widget build(BuildContext context) { final user = FirebaseAuth.instance.currentUser!; return Scaffold( body: StreamBuilder<User?>( builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center( child: CircularProgressIndicator(), ); } else if (snapshot.hasError) { return Center( child: Text('wrong'), ); } else if (snapshot.hasData) { return bottomNavigationBar(); } else if (user.phoneNumber == '') { return PhoneVerification(); } else if (FirebaseAuth.instance.currentUser!.phoneNumber! == true) { return AuthPage(); } else if (FirebaseAuth.instance.currentUser!.email! == true) { return bottomNavigationBar(); } else { return PhoneVerification(); } }, stream: FirebaseAuth.instance.authStateChanges(), )); } }
问题根源
- 提前强制解包空值:
final user = FirebaseAuth.instance.currentUser!;在APP启动时,用户未登录时currentUser为null,用!强制解包直接触发空指针。 - 逻辑判断错误:将字符串类型的
phoneNumber/email与布尔值true比较,完全不符合逻辑;且判断phoneNumber == ''错误,未登录时phoneNumber是null而非空字符串。 - StreamBuilder逻辑顺序混乱:在StreamBuilder外部提前获取用户信息,未等待auth状态流返回数据就做判断。
修复方案
第一步:修正WhichScreen页面的空指针与逻辑顺序
import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:thrifty/auth/auth_page.dart'; import '../screens/bottom_navigation_bar.dart'; import '../screens/home.dart'; import 'phone_verification.dart'; class WhichScreen extends StatefulWidget { const WhichScreen({super.key}); @override State<WhichScreen> createState() => _WhichScreenState(); } class _WhichScreenState extends State<WhichScreen> { @override Widget build(BuildContext context) { return Scaffold( body: 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('出现错误,请重试')); } // 用户已登录,直接进入主页面 if (snapshot.hasData) { return bottomNavigationBar(); } // 未登录状态,进入手机号验证页面 return PhoneVerification(); }, ), ); } }
第二步:在OTP验证完成后判断邮箱关联状态
在PhoneVerification页面的OTP验证成功回调中,添加邮箱关联判断逻辑:
// 示例:OTP验证成功后的处理逻辑 void verifyOTP(String otpCode) async { try { // 假设已获取PhoneAuthCredential PhoneAuthCredential credential = PhoneAuthProvider.credential( verificationId: verificationId, smsCode: otpCode ); // 完成手机号登录 await FirebaseAuth.instance.signInWithCredential(credential); final currentUser = FirebaseAuth.instance.currentUser; if (currentUser != null) { // 检查用户是否关联邮箱 if (currentUser.email != null && currentUser.email!.isNotEmpty) { // 已关联邮箱,跳转到邮箱登录页面 Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => AuthPage())); } else { // 未关联邮箱,跳转到注册页面绑定邮箱和设置密码 Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => RegisterEmailPage())); } } } catch (e) { // 处理验证错误,比如弹窗提示 ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('OTP验证失败:$e'))); } }
说明
- 先通过StreamBuilder监听auth状态,确保只有在状态稳定后再处理页面跳转。
- 邮箱关联判断必须放在手机号OTP验证成功后,此时用户已通过手机号登录,能正确获取到用户信息,避免空指针。
- 移除所有不必要的强制解包
!,改用空安全判断(!= null)处理可能的空值。
内容的提问来源于stack exchange,提问作者Ibtissam
相关产品推荐
相关产品推荐

