消息回执
功能简介
消息已读回执,是指用户在会话中发送一条消息后,得知其他用户已读或未读此消息。本功能可用于在企业办公等需要实时知晓消息是否已经被阅读的场景。

本文档介绍了如何使用 ZIM SDK 的接口,实现发送一条附带回执的消息,以及查看和应答回执详情等功能。
ZIM SDK 目前支持发送“单聊”会话和“群组”会话的消息回执(仅支持普通消息和富媒体消息),暂不支持发送“房间”会话的消息回执。
实现流程
消息发送端通过 ZIM SDK 发送一条消息,并通过设置 ZIMMessageSendConfig 的 hasReceipt 字段标记该消息是否需要带回执,接收端可根据消息的回执状态 receiptStatus 判断该消息当前是否带回执,或者回执处于正在进行中还是已完成,从而渲染不同的 UI 效果,而接收端可根据不同的场景进行不同的已读方式。

发送一条附带回执的消息
如果客户端 A 想要向客户端 B 发送一条附带回执的消息:
- 客户端 A 和 客户端 B 登录 ZIM SDK;
- 客户端 A 调用 sendMessage 接口,向客户端 B 发送一条消息(仅支持“单聊”会话和“群组”会话的 ZIMTextMessage、 ZIMImageMessage、 ZIMFileMessage、 ZIMAudioMessage、 ZIMVideoMessage、 ZIMCombineMessage 和 ZIMMultipleMessage),并设置 ZIMMessageSendConfig 的
hasReceipt字段为 true;
- 客户端 B 通过监听相关回调( messageReceived 或 messageReceived )会收到一条
receiptStatus为PROCESSING的消息。
接收端对消息回执进行已读操作
已读操作分为消息已读和会话已读。
消息已读
消息已读,是指接收端收到对方发送的附带回执的消息,可对该消息设置已读,已读成功,发送方将会收到该消息已被读的通知。
- 消息可为单条消息或批量消息,但是消息发送端与接收端必须在同一会话内,不允许跨会话。
- 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息。
- 客户端 B 通过相关回调( messageReceived 或 messageReceived )收到客户端 A 发送的一条附带回执的消息;
- 客户端 B 根据回调的
receiptStatus字段判断该消息的回执状态。如果是该字段为PROCESSING,表示该消息处于“回执中”,开发者可根据自己的业务逻辑,调用 sendMessageReceiptsRead 接口将该消息设置为已读。 - 客户端 B 通过 ZIMMessageReceiptsReadSentResult 得知设置是否成功。
- 客户端 A 通过 ZIMEventHandler 的 onMessageReceiptChanged 收到该消息被设置为消息已读的回调通知。开发者可根据这个回调,在客户端 A 实现将此消息设置为已读的业务逻辑。
会话已读
会话已读,是指接收端将指定会话内所有已接收的对方消息都设置为已读。
- 目前 ZIM SDK 只允许在单聊会话实现此功能;
- 此功能只作用于设置已读之前获取的消息,不对设置之后的消息生效。
- 此功能建议在用户从会话列表页进入到会话时使用,不推荐在同一会话中与 sendMessageReceiptsRead 接口混用。
- 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息。
- 客户端 B 根据回调 messageReceived 的
receiptStatus字段判断该消息的回执状态。如果是该字段为PROCESSING,则表示该消息处于回执中,开发者可根据自己的业务逻辑,调用 sendConversationMessageReceiptRead 接口将会话内客户端 A 已发送的所有消息都设置为已读。 - 客户端 B 通过 ZIMConversationMessageReceiptReadSentResult 得知设置是否成功。
- 客户端 A 通过 ZIMEventHandler 的 conversationMessageReceiptChanged 收到该消息被设置为会话已读的回调通知,开发者可根据这个回调,实现该会话所有对方发的消息都设置为已读的逻辑。开发者可根据这个回调,在客户端 A 实现自己发的所有消息都被客户端 B 设置为已读的业务逻辑。
更多功能
获取回执已读时间
通过 ZIMMessageReceiptInfo.readTime 可获取消息的回执已读时间,实现阅后即焚等密聊业务场景。
支持的接口:queryMessageReceiptsInfo、onMessageReceiptChanged。
- 对于消息发送者:当该消息被会话内成员全部已读时,已读时间才会有值,且为最后一个成员已读时的服务端时间戳,否则为 0。
- 对于消息接收者:已读时间为调用 sendMessageReceiptsRead 成功时的服务端时间戳,否则为 0。
- 获取回执已读时间暂不支持“会话已读”。
- 2.22.0 版本开始支持。
批量查询消息的回执状态、已读用户数和未读用户数
当需要查询一条或一批消息的回执状态、已读用户数和未读未读用户数时,可以调用 queryMessageReceiptsInfo 接口查询,通过 ZIMMessageReceiptsInfoQueriedResult 获取相关信息。
- 如果是查询其他用户发送的信息,得到的已读用户数和未读用户数都是 0。
- 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息。
查询群组里自己发送的消息的已读和未读成员列表
ZIM SDK 支持查询群组里自己发送的消息的已读成员列表和未读成员列表。
查询已读成员列表
当需要查询有哪些成员读了自己发送的消息,可调用 queryGroupMessageReceiptReadMemberList 接口查询具体成员列表。
如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息。
查询未读成员列表
当需要查询还有哪些成员未读自己发送的消息,可调用 queryGroupMessageReceiptUnreadMemberList 接口查询具体成员列表。
- 若 SDK 版本低于 2.16.0,当群成员人数大于 100 时,此接口不会返回具体未读成员列表。如需使用此功能,可联系 ZEGO 技术支持。
- 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息。
// 1、注册回调
// 对方设置了消息的已读回执
zim.on('messageReceiptChanged', (zim: ZIM, data: ZIMMessageReceiptChangedEventResult) => {
console.log('messageReceiptChanged', data);
});
// 对方设置了会话的已读回执
zim.on('conversationMessageReceiptChanged', (zim: ZIM, data: ZIMMessageReceiptChangedEventResult) => {
console.log('conversationMessageReceiptChanged', data);
});// 2、用户 A 发送一条消息给用户 B,并带上回执,以单聊文本消息为例
const userID_A = "xxxx" ; // 用户 A 的 ID
const userID_B = "xxxx" ; // 用户 B 的 ID
const messageObj: ZIMMessage = { type: 1, message: '文本回执消息' }
const config: ZIMMessageSendConfig = {
priority: 1, // 消息优先级,取值为 低:1 默认, 中:2, 高:3
hasReceipt: true // 设置消息带回执
}
const notification: ZIMMessageSendNotification = {
onMessageAttached: (message: ZIMMessage) => {
// todo: Loading
}
}
zim.sendMessage(messageObj, userID_B, 0, config, notification)
.then((res: ZIMMessageSentResult) => {
// 发送成功
})
.catch((err: ZIMError) => {
// 发送失败
});
// 3、用户 B 接收到带回执的消息,并做已读操作,选择以下任一接口即可
// 3.1 消息已读
const messages: ZIMMessage[] = []; // 从 queryHistoryMessage 查询,或者从 peerMessageReceived 接收
zim.sendMessageReceiptsRead(messages, userID_A, 0)
.then((res: ZIMMessageReceiptsReadSentResult) => {
// 操作成功,设置已读失败的消息通过 res.errorMessageIDs 返回
})
.catch((err: ZIMError) => {
// 操作失败
});
// 3.2、会话已读
zim.sendConversationMessageReceiptRead(userID_A, 0)
.then((res: ZIMConversationMessageReceiptReadSentResult) => {
// 操作成功,用户 B 可把这个会话内用户 A 发的消息都标志为已读
})
.catch((err: ZIMError) => {
// 操作失败
});
// 4、(可选)用户 A 查询一批消息的回执状态、未读用户数和已读用户数
const messages: ZIMMessage[] = []; // 从 queryHistoryMessage 查询
zim.queryMessageReceiptsInfo(messages, userID_B, 0)
.then((res: ZIMMessageReceiptsInfoQueriedResult) => {
// 操作成功,查询失败的消息通过 res.errorMessageIDs 返回
})
.catch((err: ZIMError) => {
// 操作失败
});
// 5、(可选)查询某一条群消息的已读群成员列表和未读群成员列表
const groupMsgObj: ZIMMessage = {} // 从 queryHistoryMessage 查询
const queryConfig: ZIMGroupMessageReceiptMemberQueryConfig = {
count: 10, // 需要查询的用户数量
nextFlag: 0 // 查询的 flag,初始时填 0,后续填从 Promise 里返回的 nextFlag
}
// 5.1 群已读用户列表
zim.queryGroupMessageReceiptReadMemberList(groupMsgObj, groupMsgObj.conversationID, queryConfig)
.then((res: ZIMGroupMessageReceiptMemberListQueriedResult) => {
// 操作成功
})
.catch((err: ZIMError) => {
// 操作失败
});
// 5.2 群未读用户列表
zim.queryGroupMessageReceiptUnreadMemberList(groupMsgObj, groupMsgObj.conversationID, queryConfig)
.then((res: ZIMGroupMessageReceiptMemberListQueriedResult) => {
// 操作成功
})
.catch((err: ZIMError) => {
// 操作失败
});获取回执消息的已送达状态
发送者发送回执消息后,若接收端设备已收到该消息,那么消息的回执状态将变更为已送达。开发者可通过 onMessageReceiptChanged 回调监听回执状态的变化。
ZIM 3.1.0 版本起,消息回执在 “回执中” 和 “已完成” 之间新增了 “已送达” 状态,用于表示回执消息已送达。如需使用此功能,请联系 ZEGO 技术支持。
以下场景的消息回执状态会变更为 “已送达” 并触发 onMessageReceiptChanged 回调。
单聊场景:
- 接收端在线收到消息后,SDK 自动确认已送达。
- 接收端收到离线推送后调用服务端 API 确认已送达。
- 无离线推送时,本端上线拉取到消息后 SDK 自动确认已送达。
群聊场景:
- 当所有群成员都已送达且仍有成员未读时,消息回执状态流转为 “已送达”。
离线推送送达不代表消息本身送达,必须 ZIM message 实际送达到接收端或通过服务端 API 确认,才会流转为 “已送达”。
如果您需要在消息接收方收到离线推送后使得消息回执状态在发送端变更为 “已送达”(iOS 可通过开启推送拦截,Android FCM 可通过使用 DataMessage 推送消息类型的方式,国内 Android 厂商暂不支持),可在收到推送后调用 服务端 API - 设置群聊消息已送达回执 进行确认。
查询群消息回执状态的成员列表
调用 queryGroupMessageReceiptMemberList 可查询群消息的已读、未读(未送达)、或已送达状态的成员列表。
参数说明:
| 参数 | 说明 |
|---|---|
| message | 需要查询的带回执的消息。 |
| groupID | 对应群会话的群 ID。 |
| count | 查询的人数,单次查询不超过 100。 |
| config | 查询的配置项:ZIMGroupMessageReceiptMemberQueryConfig,可以配置查询起始标记 nextFlag 以及查询项(已读、未读[未送达]、已送达)。 |
| 返回值 | 说明 |
|---|---|
| ZIMGroupMessageReceiptMemberListQueriedResult | 查询结果的回调,其中 userList 为符合查询条件的群成员列表,nextFlag 为下一次查询的起始标记(当 nextFlag 为 0 时表示查询完毕)。 |
调用示例:
// 1. 构造查询配置
const config = new ZIMGroupMessageReceiptMemberListQueryConfig();
config.nextFlag = 0; // 初始填 0,后续填 result 里返回的 nextFlag
config.filterType = ZIMMessageReceiptFilterType.Read; // 默认值,查已读成员
// 2. 调用接口
zim.queryGroupMessageReceiptMemberList(message, groupID, 10, config)
.then((result) => {
// 查询成功
// result.userList — List<ZIMGroupMemberInfo>,符合查询条件的群成员列表
// result.nextFlag — 下一次查询的起始标记,为 0 时表示查询完毕
// result.groupID — 群组 ID
// result.errorInfo — ZIMError,code 为 0 表示成功
})
.catch((error) => {
// 查询失败
});