当前页

消息回执

2026-09-09

功能简介

消息回执是指发送方发送一条附带回执的消息后,可以知晓该消息在接收端的送达与阅读情况。回执状态覆盖“回执中 → 已送达 → 已完成(已读)”的完整流转,也包含“已失败”“已过期”等异常状态。本功能可用于企业办公等需要实时知晓消息是否已被送达、是否已被阅读的场景。

3_消息回执_中文.png

本文档介绍了如何使用 ZIM SDK 的接口,实现发送一条附带回执的消息,以及查看和应答回执详情等功能。

注意

ZIM SDK 目前支持发送“单聊”会话和“群组”会话的消息回执(仅支持普通消息和富媒体消息),暂不支持发送“房间”会话的消息回执。

实现流程

消息发送端通过 ZIM SDK 发送一条消息,并通过设置 ZIMMessageSendConfighasReceipt 字段标记该消息是否需要带回执,接收端可根据消息的回执状态 receiptStatus 判断该消息是否带回执以及回执的当前进度,从而渲染不同的 UI 效果,而接收端可根据不同的场景进行不同的已读方式。

其中,receiptStatus 的取值来自枚举 ZIMMessageReceiptStatus

取值说明
NONE不是回执
PROCESSING回执中
DELIVERED已送达(3.1.0 及以上版本支持)
DONE已完成,即已被已读
FAILED已失败
EXPIRED已过期
UNKNOWN未知

发送一条附带回执的消息

如果客户端 A 想要向客户端 B 发送一条附带回执的消息:

  1. 客户端 A 和 客户端 B 登录 ZIM SDK;
  1. 客户端 A 调用 sendMessage 接口,向客户端 B 发送一条消息(仅支持“单聊”会话和“群组”会话的 ZIMTextMessageZIMImageMessageZIMFileMessageZIMAudioMessageZIMVideoMessageZIMCombineMessageZIMMultipleMessage),并设置 ZIMMessageSendConfighasReceipt 字段为 true;
  1. 客户端 B 通过监听相关回调(messageReceivedWithResult)会收到一条 receiptStatusPROCESSING 的消息。

接收端对消息回执进行已读操作

已读操作分为消息已读会话已读

消息已读

消息已读,是指接收端收到对方发送的附带回执的消息,可对该消息设置已读,已读成功,发送方将会收到该消息已被读的通知。

注意
  • 消息可为单条消息或批量消息,但是消息发送端与接收端必须在同一会话内,不允许跨会话。
  • 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息
  1. 客户端 B 通过相关回调(messageReceivedWithResult)收到客户端 A 发送的一条附带回执的消息;
  2. 客户端 B 根据回调的 receiptStatus 字段判断该消息的回执状态。如果是该字段为 PROCESSING,表示该消息处于“回执中”,开发者可根据自己的业务逻辑,调用 sendMessageReceiptsRead 接口将该消息设置为已读。
  3. 客户端 B 通过 ZIMMessageReceiptsReadSentCallback 得知设置是否成功。
  4. 客户端 A 通过 ZIMEventHandlermessageReceiptChanged 收到该消息被设置为消息已读的回调通知。开发者可根据这个回调,在客户端 A 实现将此消息设置为已读的业务逻辑。

会话已读

会话已读,是指接收端将指定会话内所有已接收的对方消息都设置为已读。

注意
  • 目前 ZIM SDK 只允许在单聊会话实现此功能;
  • 此功能只作用于设置已读之前获取的消息,不对设置之后的消息生效。
  • 此功能建议在用户从会话列表页进入到会话时使用,不推荐在同一会话中与 sendMessageReceiptsRead 接口混用。
  • 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息
  1. 客户端 B 根据回调 messageReceivedWithResultreceiptStatus 字段判断该消息的回执状态。如果是该字段为 PROCESSING,则表示该消息处于回执中,开发者可根据自己的业务逻辑,调用 sendConversationMessageReceiptRead 接口将会话内客户端 A 已发送的所有消息都设置为已读。
  2. 客户端 B 通过 ZIMConversationMessageReceiptReadSentCallback 得知设置是否成功。
  3. 客户端 A 通过 ZIMEventHandlerconversationMessageReceiptChanged 收到该消息被设置为会话已读的回调通知,开发者可根据这个回调,实现该会话所有对方发的消息都设置为已读的逻辑。开发者可根据这个回调,在客户端 A 实现自己发的所有消息都被客户端 B 设置为已读的业务逻辑。

更多功能

获取回执已读时间

通过 ZIMMessageReceiptInfo.readTime 可获取消息的回执已读时间,实现阅后即焚等密聊业务场景。

支持的接口:queryMessageReceiptsInfoByMessageListmessageReceiptChanged

注意
  • 对于消息发送者:当该消息被会话内成员全部已读时,已读时间才会有值,且为最后一个成员已读时的服务端时间戳,否则为 0。
  • 对于消息接收者:已读时间为调用 sendMessageReceiptsRead 成功时的服务端时间戳,否则为 0。
  • 获取回执已读时间暂不支持“会话已读”
  • 2.22.0 版本开始支持。

批量查询消息的回执状态、已读用户数和未读用户数

当需要查询一条或一批消息的回执状态、已读用户数和未读未读用户数时,可以调用 queryMessageReceiptsInfoByMessageList 接口查询,通过 ZIMMessageReceiptsInfoQueriedCallback 获取相关信息。

注意
  • 如果是查询其他用户发送的信息,得到的已读用户数和未读用户数都是 0。
  • 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息

查询群组里自己发送的消息的已读和未读成员列表

ZIM SDK 支持查询群组里自己发送的消息的已读成员列表和未读成员列表。

查询已读成员列表

当需要查询有哪些成员读了自己发送的消息,可调用 queryGroupMessageReceiptReadMemberListByMessage 接口查询具体成员列表。

注意

如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息

查询未读成员列表

当需要查询还有哪些成员未读自己发送的消息,可调用 queryGroupMessageReceiptUnreadMemberListByMessage 接口查询具体成员列表。

注意
  • 若 SDK 版本低于 2.16.0,当群成员人数大于 100 时,此接口不会返回具体未读成员列表。如需使用此功能,可联系 ZEGO 技术支持。
  • 如需对会话的历史消息进行相关操作,需先完成查询历史消息,对历史消息的回执状态进行判断,详情请参考 查询历史消息
- (void)zim:(ZIM *)zim messageReceiptChanged:(NSArray<ZIMMessageReceiptInfo *> *)infos{
     // 对方设置了消息的已读回执
}

- (void)zim:(ZIM *)zim conversationMessageReceiptChanged:(NSArray<ZIMMessageReceiptInfo *> *)infos{
    // 对方设置会话的已读回执
}



NSString *conversationID = @"xxx" ; // 会话 ID

// 用户 A 发送一条消息,并带上回执,以单聊文本消息为例

ZIMTextMessage *message = [[ZIMTextMessage alloc] init];
ZIMMessageSendConfig *sendConfig = [[ZIMMessageSendConfig alloc]init];
sendConfig.hasReceipt = true;    // 设置消息带回执
[self.zim sendMessage:cmdMsg toUserID:toUserID conversationType:type config:config notification:notification callback:^((ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo)) {
    // 开发者可以通过该回调监听消息是否发送成功。
    if (errorInfo.code == 0) {
        // 这里表示发送消息成功,message 的 receiptStatus 会为 PROCESSING,业务层可根据这个标志实现展示回执中(消息未读)的逻辑。
    }
}];


// 用户 B 接收到回执,并做已读操作,选择以下任一接口即可

// 消息已读
NSMutableArray<ZIMMessage *> *messageList = [[NSMutableArray alloc] init];

[[ZIM getInstance] sendMessageReceiptsRead:messageList conversationID:@"conversationID" conversationType:conversationType callback:^(NSString * _Nonnull conversationID, ZIMConversationType conversationType, NSArray<NSNumber *> * _Nonnull errorMessageIDs, ZIMError * _Nonnull errorInfo) {
     // 设置消息已读的回调
}];

// 会话已读

[[ZIM getInstance] sendConversationMessageReceiptRead:@"conversationID" conversationType:conversationType callback:^(NSString * _Nonnull conversationID, ZIMConversationType conversationType, ZIMError * _Nonnull errorInfo) {
    // 设置会话已读的回调
}];

// (可选)查询一批消息的回执状态、未读用户数和已读用户数

NSMutableArray<ZIMMessage *> *messageList = [[NSMutableArray alloc] init];
[[ZIM getInstance] queryMessageReceiptsInfoByMessageList:messageList conversationID:conversationID conversationType:conversationType callback:^(NSArray<ZIMMessageReceiptInfo *> * _Nonnull infos, NSArray<NSNumber *> * _Nonnull errorMessageIDs, ZIMError * _Nonnull errorInfo) {
     // 查询到这一批消息的状态和数量,遍历 infos 获取对应    的消息 ID 和 count
}];


// (可选)查询某一条群消息的已读群成员列表和未读群成员列表

// 已读用户列表
ZIMGroupMessageReceiptMemberQueryConfig *config =  [[ZIMGroupMessageReceiptMemberQueryConfig alloc]init];
config.nextFlag = 0;    // 查询的 flag ,初始时填 0,后续填从 callback 里返回的 flag。
config.count = 10;    // 需要查询的用户数量。

[[ZIM getInstance] queryGroupMessageReceiptReadMemberListByMessage:message groupID:groupID config:config callback:^(NSString * _Nonnull groupID, NSArray<ZIMGroupMemberInfo *> * _Nonnull userList, unsigned int nextFlag, ZIMError * _Nonnull errorInfo)    {
    // 查询到对应的成员列表
}];


// 未读用户列表
ZIMGroupMessageReceiptMemberQueryConfig config = new ZIMGroupMessageReceiptMemberQueryConfig();
config.nextFlag = 0;    // 查询的 flag ,初始时填 0,后续填从 callback 里返回的 flag。
config.count = 10;    // 需要查询的用户数量。

[[ZIM getInstance] queryGroupMessageReceiptUnreadMemberListByMessage:message groupID:groupID config:config callback:^(NSString * _Nonnull groupID, NSArray<ZIMGroupMemberInfo *> * _Nonnull userList, unsigned int nextFlag, ZIMError * _Nonnull errorInfo) {
    // 查询到对应的成员列表
}];

获取回执消息的已送达状态

发送者发送回执消息后,若接收端设备已收到该消息,那么消息的回执状态将变更为已送达。开发者可通过 messageReceiptChanged 回调监听回执状态的变化。

注意

ZIM 3.1.0 版本起,消息回执在 “回执中” 和 “已完成” 之间新增了 “已送达” 状态,用于表示回执消息已送达,单聊和群聊均支持,无需额外开通。若使用 3.1.0 之前的版本需要此能力,请联系 ZEGO 技术支持评估。

以下场景的消息回执状态会变更为 “已送达” 并触发 messageReceiptChanged 回调。

单聊场景:

  • 接收端在线收到消息后,SDK 自动确认已送达。
  • 接收端收到离线推送后调用服务端 API 确认已送达。
  • 无离线推送时,本端上线拉取到消息后 SDK 自动确认已送达。

群聊场景:

  • 当所有群成员都已送达且仍有成员未读时,消息回执状态流转为 “已送达”。
注意

离线推送送达不代表消息本身送达,必须 ZIM message 实际送达到接收端或通过服务端 API 确认,才会流转为 “已送达”。

如果您需要在消息接收方收到离线推送后使得消息回执状态在发送端变更为 “已送达”(iOS 可通过开启推送拦截,Android FCM 可通过使用 DataMessage 推送消息类型的方式,国内 Android 厂商暂不支持),可在收到推送后调用 服务端 API - 设置群聊消息已送达回执 进行确认。

回执有效期与已过期状态

消息回执的有效期为 7 天。超出有效期后,消息的回执状态将流转为“已过期”(EXPIRED),且不再支持对该消息继续进行已读操作。

开发者可通过 messageReceiptChanged 回调实时感知回执过期状态的变化(2.16.0 及以上版本支持),建议在 UI 层将过期消息的回执标识置灰或移除。

查询群消息回执状态的成员列表

调用 queryGroupMessageReceiptMemberListByMessage 可查询群消息的已读、未读(未送达)、或已送达状态的成员列表。

参数说明:

参数说明
message需要查询的带回执的消息。
groupID对应群会话的群 ID。
count查询的人数,单次查询不超过 100。
config查询的配置项:ZIMGroupMessageReceiptMemberQueryConfig,可以配置查询起始标记 nextFlag 以及查询项(已读、未读[未送达]、已送达)。
callback查询结果的回调:ZIMGroupMessageReceiptMemberListQueriedCallback,其中 userList 为符合查询条件的群成员列表,nextFlag 为下一次查询的起始标记(当 nextFlag 为 0 时表示查询完毕)。

调用示例:

ZIMGroupMessageReceiptMemberQueryConfig *config = [[ZIMGroupMessageReceiptMemberQueryConfig alloc] init];
config.nextFlag = 0;    // 查询的起始标记,初始填 0,后续填从 callback 里返回的 nextFlag。
config.count = 10;      // 需要查询的用户数量,单次不超过 100。

[zim queryGroupMessageReceiptMemberListByMessage:message
                                         groupID:groupID
                                           count:count
                                          config:config
                                        callback:^(NSString *_Nonnull groupID, NSArray<ZIMGroupMemberInfo *> *_Nonnull userList,
                                                   unsigned int nextFlag, ZIMError *_Nonnull errorInfo) {
    if (errorInfo.code == 0) {
        // 查询成功,userList 为符合查询条件的群成员列表
        // nextFlag 为下一次查询的起始标记,nextFlag 为 0 时表示查询完毕
    } else {
        // 查询失败
    }
}];

上一篇

搜索本地消息

下一篇

消息表态