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

Flutter中如何将Firestore自动生成文档ID替换为用户手机号并实现注册时手机号查重

解决方案:Firestore文档ID替换为手机号 + 注册时重复校验

针对你提出的两个需求,我来一步步帮你修改代码:

1. 将Firestore文档ID改为用户手机号

你当前代码里用的是Firebase Auth生成的user!.uid作为文档ID,要改成用户手机号很简单,只需要把doc(user!.uid)替换为用户输入的手机号即可。不过要注意统一手机号格式(比如去掉空格、区号等),避免同一个手机号因为格式不同被存成多个文档。

修改后的postDataToFirestore函数如下:

postDataToFirestore() async {
  FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
  // 统一手机号格式:去掉所有空格
  String processedPhone = phoneController.text.replaceAll(RegExp(r'\s+'), '');

  UserModel userModel = UserModel();
  // 用处理后的手机号作为uid和phone字段
  userModel.uid = processedPhone;
  userModel.name = nameController.text;
  userModel.email = emailController.text;
  userModel.phone = processedPhone;
  userModel.province = dropDownValue;
  userModel.dateOfBirth = dateController.text;
  userModel.challengeHistory = [];
  userModel.challengeMember = [];
  userModel.profileImage = 'https://firebasestorage.googleapis.com/v0/b/athaddak-bf02c.appspot.com/o/default_picture%2FBlank-Avatar.png?alt=media&token=47255868-37a0-4a55-8bc4-1d1ef5599ded';
  userModel.challenges = 0;
  userModel.winnings = 0;
  userModel.events = 0;
  userModel.points = 20;

  // 用处理后的手机号作为文档ID
  await firebaseFirestore
      .collection("Users")
      .doc(processedPhone)
      .set(userModel.toMap());

  Fluttertoast.showToast(msg: "Account Created Successfully .. :)");
  Navigator.pushAndRemoveUntil(
      (context),
      MaterialPageRoute(builder: (context) => HomeScreen()),
          (route) => false);
}

2. 注册时检查手机号是否重复

要避免重复注册,我们需要在创建Auth用户之前先检查手机号是否已存在,同时可以配合Firestore的唯一索引防止并发场景下的重复写入。

方式一:注册前主动查询Firestore

修改你的signUp函数,先校验表单,再查询手机号是否已存在,只有不存在时才创建用户:

void signUp(String email, String password) async {
  if (_formKey.currentState!.validate()) {
    // 先统一手机号格式
    String processedPhone = phoneController.text.replaceAll(RegExp(r'\s+'), '');
    
    // 查询该手机号对应的文档是否存在
    var docSnapshot = await FirebaseFirestore.instance.collection("Users").doc(processedPhone).get();
    if (docSnapshot.exists) {
      Fluttertoast.showToast(msg: "该手机号已注册,请更换其他手机号");
      return;
    }

    // 手机号不存在,继续创建Auth用户
    await _auth
        .createUserWithEmailAndPassword(email: email, password: password)
        .then((value) => {postDataToFirestore()})
        .catchError((e) {
      Fluttertoast.showToast(msg: e!.message);
    });
  }
}

方式二:添加Firestore唯一索引(可选但推荐)

如果担心并发场景(比如两个用户同时用同一个手机号点击注册),可以在Firestore控制台给Users集合的phone字段设置唯一索引:

  1. 打开Firebase控制台 → Firestore数据库 → 索引
  2. 创建复合索引,集合选Users,字段选phone(升序),勾选"唯一"选项
  3. 保存索引,等待生效

这样即使并发写入,Firestore会自动拒绝重复的手机号写入,你可以在catchError里捕获这个错误并提示用户:

.catchError((e) {
  if (e.toString().contains("unique")) {
    Fluttertoast.showToast(msg: "该手机号已注册,请更换其他手机号");
  } else {
    Fluttertoast.showToast(msg: e!.message);
  }
});

优化手机号输入框的校验

你还可以在手机号输入框的validator里添加格式校验,提前过滤无效输入:

final phoneField = TextFormField(
  controller: phoneController,
  keyboardType: TextInputType.phone,
  autofocus: false,
  autocorrect: false,
  textInputAction: TextInputAction.next,
  validator: (value) {
    if (value!.isEmpty) {
      return "Please Enter a Phone Number";
    }
    // 校验手机号格式(示例为中国11位手机号,可根据你的需求调整正则)
    String cleanedPhone = value.replaceAll(RegExp(r'\s+'), '');
    if (!RegExp(r'^1[3-9]\d{9}$').hasMatch(cleanedPhone)) {
      return "Please Enter a Valid Phone Number";
    }
    return null;
  },
  onSaved: (value) {
    phoneController.text = value!;
  },
  textAlign: TextAlign.center,
  decoration: InputDecoration(
    prefixIcon: Icon(Icons.phone),
    contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
    hintText: AppLocalizations.of(context)!.phoneNumber,
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(10),
    ),
  ),
);

这样就能完美实现你的两个需求啦!

内容的提问来源于stack exchange,提问作者editix

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 16:42:40