实现消息回执
实现消息回执
功能说明
消息送达回执 表示消息已成功送达接收方设备。接收方开启该能力后,收到单聊消息时 SDK 会自动向发送方回发送达回执。发送方可通过送达回执确认消息是否已经到达对方客户端。
消息已读回执 表示接收方已阅读指定消息。接收方阅读消息后,需要发送消息已读回执,消息发送方收到回执后可更新对应消息的已读状态。
消息送达回执和已读回执的效果示例,如下图所示:

使用限制
- 单聊会话支持消息送达回执和消息已读回执。
- 群聊会话支持消息已读回执,不支持消息送达回执。
- 聊天室暂不支持消息送达回执和消息已读回执。
- 群聊消息已读回执需要在 环信控制台开通该功能。
技术原理
单聊消息送达回执
实现单聊消息送达回执的流程如下:

实现该功能的基本步骤如下:
- 消息接收方在调用
ChatClient#init前,通过ChatOptions#requireDeliveryAck开启送达回执功能。该配置默认为false,如需送达回执必须设置为true。 - 消息发送方通过
ChatManager#addEventHandler注册消息事件监听器,并通过ChatEventHandler#onMessagesDelivered监听送达回执。 - 消息接收方收到单聊消息后,SDK 自动向消息发送方发送送达回执,无需应用手动调用接口。
- 消息发送方收到
onMessagesDelivered回调后,表示消息已送达接收方客户端。应用可据此更新消息的展示状态,也可通过ChatMessage#hasDeliverAck查询消息是否已送达。
提示
消息送达回执仅支持单聊,不支持群聊和聊天室。
消息已读回执
Flutter SDK 使用 ChatManager#sendMessageReadReceipts 统一发送单聊和群聊消息的已读回执,消息发送方通过 ChatEventHandler#onMessageReadReceipts 接收回执。
实现消息已读回执的基本流程如下:

实现该功能的基本步骤如下:
- 消息发送方在发送单聊或群聊消息前,将
ChatMessage#isNeedReadReceipt设置为true,设置该消息需要已读回执。 - 消息发送方通过
ChatManager#addEventHandler注册消息事件监听器,并通过ChatEventHandler#onMessageReadReceipts监听已读回执。 - 消息接收方在用户实际阅读消息后,调用
sendMessageReadReceipts发送一条或多条消息的已读回执。 - 消息发送方收到
onMessageReadReceipts回调后,可根据ChatMessageReadReceipt#messageId定位消息,并更新对应消息的已读状态。
sendMessageReadReceipts 单次最多可传入 50 条消息。所有消息必须属于同一会话,并且其 ChatMessage#isNeedReadReceipt 必须为 true。该接口仅支持单聊和群聊,不支持聊天室。
对于群聊消息,应用可以通过以下接口获取已读情况:
ChatMessageReadReceipt#readCount或ChatMessage#groupReadReceiptCount:获取群消息的已读人数。ChatManager#getGroupMessageReadReceipts:批量获取多条群消息的已读回执汇总,单次最多传入 20 条属于同一会话的消息。ChatManager#fetchGroupMessageReadReceipts:分页获取单条群消息的已读回执成员详情。
提示
发送消息已读回执不会改变会话未读数。如需清零会话未读数,应另行调用 clearConversationUnreadMessageCount;该操作不会向消息发送方发送已读回执。
前提条件
开始前,请确保满足以下条件:
单聊消息送达回执
步骤 1:开启送达回执
在调用 ChatClient#init 前,通过 ChatOptions#requireDeliveryAck 设置是否需要单聊消息送达回执。该配置默认为 false,如需送达回执必须设置为 true。
final options = ChatOptions.withAppKey(
'your-org#your-app',
requireDeliveryAck: true,
);
await ChatClient.getInstance.init(options);
开启后,接收方收到单聊消息时由 SDK 自动发送送达回执,无需应用主动调用发送接口。
步骤 2:监听送达回执
发送方通过 ChatEventHandler#onMessagesDelivered 接收送达回执,并可通过 ChatMessage#hasDeliverAck 查询消息是否已送达。
const handlerId = 'message_receipt_handler';
ChatClient.getInstance.chatManager.addEventHandler(
handlerId,
ChatEventHandler(
onMessagesDelivered: (messages) {
for (final message in messages) {
final delivered = message.hasDeliverAck;
// 根据 delivered 更新消息的送达状态。
}
},
),
);
// 不再需要监听时移除监听器。
ChatClient.getInstance.chatManager.removeEventHandler(handlerId);
单聊和群聊消息已读回执
单聊消息和群聊消息均支持已读回执功能。单聊消息已读回执功能默认开启,但发送方仍需在发送消息前将 ChatMessage#isNeedReadReceipt 设置为 true。单聊消息的已读回执有效期与消息在服务端的存储时间一致,即在服务器存储消息期间均可发送已读回执。消息在服务端的存储时间与你订阅的套餐包有关,详见 IM 套餐包功能详情。
群消息已读回执功能存在以下使用限制:
| 使用限制 | 默认设置 | 说明 |
|---|---|---|
| 功能开通 | 关闭 | 使用前需在 环信控制台 的 即时通讯 > 基础功能 > 消息与会话 页面开通 群聊消息已读回执。 |
| 使用权限 | 所有群成员 | 默认情况下,所有群成员发送消息时均可要求已读回执。若只允许群主和群管理员要求已读回执,请联系商务调整配置。 |
| 已读回执有效期 | 3 天 | 群消息已读回执的有效期为 3 天。消息发送时间超过 3 天后,服务器不再记录阅读该消息的群成员,也不会再发送该消息的已读回执。 |
| 群规模 | 200 人 | 该功能最多支持 200 人的群组。群成员数量超过 200 后,群消息不会返回已读回执,该上限目前无法提升。 |
| 查看已读人数 | 消息发送方 | 默认仅消息发送方可以查看群消息的已读人数。如需允许所有群成员查看,请联系商务开通。 |
步骤 1:设置消息需要已读回执
发送单聊或群聊消息前,将 ChatMessage#isNeedReadReceipt 设置为 true,设置需要消息已读回执。该属性对单聊和群聊均有效。
单聊消息已读回执无需额外开通。群聊消息已读回执需先在环信控制台开通功能,再设置该属性。
final message = ChatMessage.createTxtSendMessage(
targetId: conversationId,
content: content,
chatType: ChatType.Chat, // 群聊时设置为 ChatType.GroupChat。
);
message.isNeedReadReceipt = true;
await ChatClient.getInstance.chatManager.sendMessage(message);
步骤 2:发送消息已读回执
接收方阅读消息后,调用 sendMessageReadReceipts 批量发送已读回执。单次最多传入 50 条消息,所有消息必须属于同一会话,且 isNeedReadReceipt 必须为 true。
final messages = <ChatMessage>[message];
try {
await ChatClient.getInstance.chatManager.sendMessageReadReceipts(messages);
// 当前批次的消息已读回执发送成功。
} on ChatError catch (e) {
// 根据错误码和错误信息处理。
debugPrint('sendMessageReadReceipts error: ${e.code}, ${e.description}');
}
提示
建议只为接收方向、属于单聊或群聊、isNeedReadReceipt 为 true 且 isPeerRead 为 false 的消息发送已读回执。视频、语音和文件等消息可在用户实际查看内容后再发送。
步骤 3:监听消息已读回执
发送方通过 ChatEventHandler#onMessageReadReceipts 统一监听单聊和群聊消息的已读回执。回调返回 List<ChatMessageReadReceipt>。每个回执对象提供以下信息:
| API | 返回类型 | 说明 |
|---|---|---|
messageId | String | 获取回执对应的消息 ID。 |
conversationId | String | 获取回执对应的会话 ID。 |
isPeerReceipt | bool | 判断是否为单聊对端发送的已读回执。 |
readCount | int | 获取群消息的已读人数。 |
const handlerId = 'message_receipt_handler';
ChatClient.getInstance.chatManager.addEventHandler(
handlerId,
ChatEventHandler(
onMessageReadReceipts: (receipts) {
for (final receipt in receipts) {
final messageId = receipt.messageId;
final conversationId = receipt.conversationId;
final peerRead = receipt.isPeerReceipt;
final readCount = receipt.readCount;
// 根据回执刷新单聊消息已读状态或群消息已读人数。
}
},
),
);
// 不再需要监听时移除监听器。
ChatClient.getInstance.chatManager.removeEventHandler(handlerId);
获取群消息已读回执详情
批量获取多条群消息的回执汇总
调用 getGroupMessageReadReceipts 从服务器批量获取多条群消息的已读回执汇总。单次最多传入 20 条消息,且所有消息必须属于同一群聊会话。
try {
final receipts = await ChatClient.getInstance.chatManager
.getGroupMessageReadReceipts(messages);
// receipts 为各消息的已读回执汇总。
} on ChatError catch (e) {
debugPrint(
'getGroupMessageReadReceipts error: ${e.code}, ${e.description}',
);
}
获取单条群消息的回执成员详情
调用 fetchGroupMessageReadReceipts 分页获取单条群消息的已读回执成员详情。目标消息必须是需要已读回执的群聊消息;pageSize 的取值范围为 [1, 50]。
首次调用时将 cursor 传入空字符串。后续调用时,将上一次结果中的 cursor 作为新的 cursor。
String cursor = '';
try {
final result = await ChatClient.getInstance.chatManager
.fetchGroupMessageReadReceipts(
messageId,
groupId,
cursor: cursor,
pageSize: 20,
);
final receipts = result.data;
final nextCursor = result.cursor;
// 保存 nextCursor,用于获取下一页。
} on ChatError catch (e) {
debugPrint(
'fetchGroupMessageReadReceipts error: ${e.code}, ${e.description}',
);
}
ChatGroupReadReceipt 提供以下信息:
receiptId:已读回执 ID,可能为null。messageId:消息 ID。from:发送回执的群成员信息,类型为GroupMemberInfo。readCount:已读人数。timestamp:已读回执时间戳。
提示
fetchGroupMessageReadReceipts 返回结果中的 totalCount 仅在 iOS 平台有值,Android 平台为 null。
事件说明
| 事件 | 触发时机 | 接收方 |
|---|---|---|
ChatEventHandler#onMessagesReceived | 收到普通消息时触发。 | 消息接收方。多设备场景下,发送方的其他在线设备也可能收到消息。 |
ChatEventHandler#onMessagesDelivered | 接收方 SDK 自动发送单聊消息送达回执后触发。 | 单聊消息发送方。 |
ChatEventHandler#onMessageReadReceipts | 接收方调用 sendMessageReadReceipts 发送一条或多条消息的已读回执后触发。 | 单聊或群聊消息发送方。 |
查看消息送达和已读状态
| API | 适用场景 | 说明 |
|---|---|---|
ChatMessage#hasDeliverAck | 单聊 | 查询消息是否已送达对端。 |
ChatMessage#isPeerRead | 单聊 | 查询对端是否已读该消息。 |
ChatMessage#groupReadReceiptCount | 群聊 | 查询群消息的已读人数。 |
ChatMessage#isRead | 单聊、群聊 | 查询该消息在当前设备上的本地已读状态。 |
ChatMessage#isNeedReadReceipt | 单聊、群聊 | 查询该消息是否需要已读回执。 |
消息已读回执与会话未读数清零
发送消息已读回执和清零会话未读数是两个独立操作:
| 操作 | 作用 | 是否通知消息发送方 | 是否改变会话未读数 |
|---|---|---|---|
sendMessageReadReceipts | 为指定消息发送已读回执。 | 是 | 否 |
clearConversationUnreadMessageCount | 清除指定会话的本地未读数,并同步当前账号的其他设备。 | 否 | 是 |
clearAllConversationUnreadMessageCount | 清除所有本地会话的未读数,并同步当前账号的其他设备。详见 会话未读数 | 否 | 是 |
注意事项
- 消息送达回执仅支持单聊,不支持群聊和聊天室。
- 消息已读回执仅支持单聊和群聊,不支持聊天室。
- 单聊和群聊消息在发送前都需要将
ChatMessage#isNeedReadReceipt设置为true。 sendMessageReadReceipts单次最多传入 50 条消息。所有消息必须属于同一会话,且其isNeedReadReceipt必须为true。- 调用
sendMessageReadReceipts的客户端不会通过onMessageReadReceipts收到自己发送的回执;该回调由原消息发送方收到。 - 群消息已读回执功能需要在环信控制台开通,并受有效期、群规模和查看权限等服务端配置限制。
接口列表
| API 名称 | 所属模块/类 | 说明 |
|---|---|---|
requireDeliveryAck | ChatOptions | 设置是否需要单聊消息送达回执。 |
init | ChatClient | 使用指定配置初始化 SDK。 |
createTxtSendMessage | ChatMessage | 创建文本消息。 |
sendMessage | ChatManager | 发送消息。 |
sendMessageReadReceipts | ChatManager | 批量发送单聊或群聊消息的已读回执。 |
messageId / conversationId | ChatMessageReadReceipt | 获取回执对应的消息 ID 和会话 ID。 |
isPeerReceipt / readCount | ChatMessageReadReceipt | 获取单聊对端回执状态或群消息已读人数。 |
getGroupMessageReadReceipts | ChatManager | 批量获取多条群消息的已读回执详情。 |
fetchGroupMessageReadReceipts | ChatManager | 分页获取单条群消息的已读回执成员详情。 |
receiptId / messageId / from / readCount / timestamp | ChatGroupReadReceipt | 获取群消息已读回执详情。 |
groupReadReceiptCount | ChatMessage | 查询群消息的已读人数。 |
clearConversationUnreadMessageCount | ChatManager | 清除指定会话的本地未读消息数。 |
clearAllConversationUnreadMessageCount | ChatManager | 清除所有本地会话的未读消息数。 |
