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

Flutter登录页实现单字段支持邮箱/手机号登录求助

实现单个输入框支持邮箱/手机号登录的解决方案

步骤1:添加验证工具方法

在_LoginState类中添加两个工具方法,用于判断输入内容是邮箱还是手机号:

// 判断是否为合法邮箱
bool isEmail(String input) => RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(input);

// 判断是否为合法手机号(可根据地区调整正则,示例为国际通用格式)
bool isPhoneNumber(String input) => RegExp(r'^\+?[0-9]{10,15}$').hasMatch(input);

步骤2:修改输入框验证规则

更新TextFormField的validator,使其支持邮箱或手机号的验证:

validator: (value) {
  if (value == null || value.isEmpty) {
    return '请输入邮箱或手机号';
  } else if (!isEmail(value) && !isPhoneNumber(value)) {
    return '请输入有效的邮箱或手机号';
  }
  return null;
}

步骤3:修改登录逻辑

更新userlogin方法,根据输入内容的类型选择对应的登录方式:

// 先导入cloud_firestore依赖
import 'package:cloud_firestore/cloud_firestore.dart';

userlogin() async {
  try {
    String loginId = emailController.text.trim();
    String password = passwordController.text.trim();

    UserCredential? userCredential;

    if (isEmail(loginId)) {
      // 邮箱直接登录
      userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: loginId,
        password: password,
      );
    } else if (isPhoneNumber(loginId)) {
      // 通过手机号查询Firestore中关联的邮箱
      QuerySnapshot snapshot = await FirebaseFirestore.instance
          .collection('users') // 替换为你的用户集合名称
          .where('phoneNumber', isEqualTo: loginId)
          .limit(1)
          .get();

      if (snapshot.docs.isEmpty) {
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          backgroundColor: Colors.orangeAccent,
          content: Text(
            '未找到该手机号对应的用户',
            style: GoogleFonts.limelight(
              fontSize: 15.0,
              color: Colors.white,
            ),
          ),
        ));
        return;
      }

      // 获取关联的邮箱后执行登录
      String userEmail = snapshot.docs.first['email'];
      userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: userEmail,
        password: password,
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        backgroundColor: Colors.orangeAccent,
        content: Text(
          '请输入有效的邮箱或手机号',
          style: GoogleFonts.limelight(
            fontSize: 15.0,
            color: Colors.white,
          ),
        ),
      ));
      return;
    }

    print(userCredential.user?.uid);
    await storage.write(key: "uid", value: userCredential.user?.uid);
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(
        builder: (context) => Waiting(),
      ),
    );
  } on FirebaseAuthException catch (e) {
    String message = '';
    if (e.code == 'user-not-found') {
      message = '未找到该用户';
    } else if (e.code == 'wrong-password') {
      message = '密码错误';
    } else {
      message = '登录失败:${e.code}';
    }
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      backgroundColor: e.code == 'wrong-password' ? Colors.redAccent : Colors.orangeAccent,
      content: Text(
        message,
        style: GoogleFonts.limelight(
          fontSize: 15.0,
          color: Colors.white,
        ),
      ),
    ));
  } catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      backgroundColor: Colors.redAccent,
      content: Text(
        '登录出错:${e.toString()}',
        style: GoogleFonts.limelight(
          fontSize: 15.0,
          color: Colors.white,
        ),
      ),
    ));
  }
}

步骤4:添加依赖

在pubspec.yaml中添加Cloud Firestore的依赖(如果尚未添加):

dependencies:
  flutter:
    sdk: flutter
  cloud_firestore: ^4.17.1 # 使用最新版本
  # 其他已有的依赖...

注意事项

  • 确保你的Firestore用户集合中,每个用户文档都存储了phoneNumber和email字段,且手机号字段唯一
  • 根据用户所在地区调整手机号的正则表达式,比如中国手机号可使用^1[3-9]\d{9}$
  • 如果你是通过Firebase Auth的手机号OTP方式注册用户,需要调整登录逻辑,改用OTP验证而非密码登录

内容的提问来源于stack exchange,提问作者Abu Bakar Farooq

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 05:25:30