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
相关产品推荐
相关产品推荐

