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

Flutter Firebase聊天问题:消息范围控制与空值检查错误修复

问题1:实现一对一聊天(仅发送方与接收方可见消息)

解决思路

通过在消息数据中存储senderId和receiverId,查询时过滤出当前用户是发送方且接收方为目标用户,或者当前用户是接收方且发送方为目标用户的消息;同时配合Firestore安全规则限制非法读取,从客户端和服务端两层保障数据权限。

代码修改

1. 消息发送时存储双方ID

修改发送逻辑,确保每条消息都包含发送方和接收方的ID:

void sendMessage(String messageText) async {
  final currentUser = FirebaseAuth.instance.currentUser;
  final receiverId = widget.id;

  // 校验用户登录状态和接收方ID有效性
  if (currentUser == null) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('请先登录账号')),
    );
    return;
  }
  if (receiverId == null) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('无法获取接收方信息,请重试')),
    );
    return;
  }

  // 写入Firestore
  await FirebaseFirestore.instance.collection('messages').add({
    'senderId': currentUser.uid,
    'receiverId': receiverId,
    'content': messageText,
    'timestamp': Timestamp.now(),
  });
}

2. 过滤查询双方的消息

修改消息列表的查询逻辑,只获取当前用户与目标用户之间的消息:

Stream<QuerySnapshot> getMessagesStream() {
  final currentUser = FirebaseAuth.instance.currentUser;
  final receiverId = widget.id;

  if (currentUser == null || receiverId == null) {
    return const Stream.empty();
  }

  return FirebaseFirestore.instance
      .collection('messages')
      .where(Filter.or(
        // 当前用户发往目标用户的消息
        Filter('senderId', isEqualTo: currentUser.uid).and(Filter('receiverId', isEqualTo: receiverId)),
        // 目标用户发往当前用户的消息
        Filter('senderId', isEqualTo: receiverId).and(Filter('receiverId', isEqualTo: currentUser.uid)),
      ))
      .orderBy('timestamp')
      .snapshots();
}

3. 设置Firestore安全规则(推荐)

在Firebase控制台的Firestore规则中添加限制,防止非法读取:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /messages/{message} {
      // 仅允许消息的发送方或接收方读取
      allow read: if request.auth != null && 
        (resource.data.senderId == request.auth.uid || resource.data.receiverId == request.auth.uid);
      // 仅允许登录用户发送自己的消息
      allow create: if request.auth != null && 
        request.resource.data.senderId == request.auth.uid;
    }
  }
}

问题2:解决“Null Check operator used on a null value”错误

问题原因

widget.id为空时,使用空断言运算符!强行解包,触发空指针错误;同时未校验currentUser的登录状态,也可能导致类似问题。

解决步骤

1. 确保接收方ID非空传递

定义聊天页面时,将id设为必填参数,从源头避免传入null:

class ChatScreen extends StatelessWidget {
  final String id; // 必填非空参数
  const ChatScreen({super.key, required this.id});

  @override
  Widget build(BuildContext context) {
    // 页面逻辑
  }
}

跳转页面时确保传入有效的ID:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => ChatScreen(id: targetUserId), // targetUserId必须为非空字符串
  ),
);

2. 使用前校验非空

在使用widget.id和currentUser前先判断是否为空,避免直接使用!:

// 发送消息时的完整校验逻辑
final currentUser = FirebaseAuth.instance.currentUser;
final receiverId = widget.id;

if (currentUser == null) {
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(content: Text('请先登录账号')),
  );
  return;
}

if (receiverId == null) {
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(content: Text('接收方信息无效,请返回重试')),
  );
  return;
}

// 后续正常使用currentUser.uid和receiverId,无需加!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 21:21:48