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

如何用Flutter+Node.js+MongoDB实现类WhatsApp通讯录好友检测

实现通讯录联系人检测功能的方案

整体流程

Flutter端获取并标准化通讯录手机号 → 发送至Node.js后端 → 后端查询MongoDB匹配已注册用户 → 返回结果给Flutter端展示


1. Flutter端处理

1.1 权限申请

  • Android:在AndroidManifest.xml中添加权限
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    
  • iOS:在Info.plist中添加权限描述
    <key>NSContactsUsageDescription</key>
    <string>需要访问通讯录来检测已注册的联系人</string>
    

1.2 获取并标准化通讯录手机号

使用flutter_contacts获取通讯录后,必须统一手机号格式(比如去除非数字字符、添加国家码),避免因格式不一致导致查询失败:

import 'package:flutter_contacts/flutter_contacts.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

// 获取并处理通讯录手机号(去重+标准化)
Future<List<String>> getStandardizedContactNumbers() async {
  if (!await FlutterContacts.requestPermission()) {
    return [];
  }
  final contacts = await FlutterContacts.getContacts(withProperties: true);
  final Set<String> uniqueNumbers = {};

  for (final contact in contacts) {
    for (final phone in contact.phones) {
      // 移除所有非数字字符
      final cleanNumber = phone.number.replaceAll(RegExp(r'\D'), '');
      // 标准化为带国家码的格式(示例为+86,可根据用户地区动态调整)
      final standardized = '+86$cleanNumber';
      uniqueNumbers.add(standardized);
    }
  }
  return uniqueNumbers.toList();
}

// 发送至后端查询已注册用户
Future<List<Map<String, dynamic>>> queryRegisteredUsers(List<String> numbers) async {
  final response = await http.post(
    Uri.parse('http://你的后端域名/api/check-contacts'),
    headers: {'Content-Type': 'application/json'},
    body: json.encode({'phoneNumbers': numbers}),
  );

  if (response.statusCode == 200) {
    return List<Map<String, dynamic>>.from(json.decode(response.body));
  } else {
    throw Exception('查询联系人失败');
  }
}

2. Node.js后端实现

2.1 接口编写(基于Express+Mongoose)

接收前端传来的手机号列表,查询MongoDB中匹配的已注册用户:

const express = require('express');
const router = express.Router();
const User = require('../models/User');

router.post('/check-contacts', async (req, res) => {
  try {
    const { phoneNumbers } = req.body;
    // 仅查询手机号在列表中的用户,返回必要字段(避免泄露敏感信息)
    const registeredUsers = await User.find(
      { phone: { $in: phoneNumbers } },
      { phone: 1, username: 1, avatar: 1, _id: 0 }
    );
    res.json(registeredUsers);
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: '服务器内部错误' });
  }
});

module.exports = router;

3. MongoDB优化

为了提升$in查询的速度,必须给用户集合的phone字段添加索引:

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  phone: { type: String, required: true, unique: true },
  username: { type: String, required: true },
  avatar: String,
  // 其他字段...
});

// 添加单字段索引,加速手机号查询
userSchema.index({ phone: 1 });

module.exports = mongoose.model('User', userSchema);

4. 隐私优化(可选)

如果担心通讯录隐私泄露,可以对手机号进行哈希处理后再传输:

  • Flutter端哈希手机号:
    import 'dart:convert';
    import 'package:crypto/crypto.dart';
    
    String hashPhone(String number) {
      return sha256.convert(utf8.encode(number)).toString();
    }
    
  • 后端存储哈希后的手机号,查询时用哈希后的列表匹配,避免明文传输和存储用户通讯录信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 03:38:06