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

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(),
    ));
  }
}

问题根源

  1. 提前强制解包空值:final user = FirebaseAuth.instance.currentUser!;在APP启动时,用户未登录时currentUser为null,用!强制解包直接触发空指针。
  2. 逻辑判断错误:将字符串类型的phoneNumber/email与布尔值true比较,完全不符合逻辑;且判断phoneNumber == ''错误,未登录时phoneNumber是null而非空字符串。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 10:05:24