即时通讯
客户端 SDK
发布日志
升级指南
当前页

实现消息送达状态与回执

2026-10-10

功能简介

ZIM 消息回执覆盖 “回执中 → 已送达 → 已完成(已读)” 的完整流转,也包含“已失败”、“已过期”等异常状态,适用于企业办公、客服工单、交易确认等需要明确消息触达状态的场景。

核心设计约束:回执状态是会话类型 + 消息类型 + 时间三重约束下实现的能力,不支持房间会话、7 天后流转为 “已过期” 且不再支持已读操作的消息。

前提条件

  • 消息回执:ZIM SDK 版本 ≥ 2.5.0;消息已送达状态:SDK ≥ 3.1.0。
  • 消息回执为付费版功能,如需使用需要开通专业版及以上版本。
说明

“已送达”状态回执需联系 ZEGO 技术支持开启;3.1.0 之前的版本如需该能力,请联系 ZEGO 技术支持评估。

实现方案

回执状态与支持范围

发送消息时需将 ZIMMessageSendConfig 的 hasReceipt 设置为 true,消息才会进入回执链路(未开启时状态为 NONE)。

2.16.0 及以上版本可通过回执变更回调实时感知过期状态变化。

回执状态(ZIMMessageReceiptStatus)
取值版本含义
NONE—非回执消息。发送时未开启 hasReceipt
PROCESSING2.5.0+回执中。接收端据此判断"这条消息需要回执",可执行已读操作
DELIVERED3.1.0+已送达。表示回执消息已送达接收端,单聊与群聊均支持
DONE2.5.0+已完成,即已被已读
FAILED—已失败
EXPIRED2.16.0+ 可实时感知已过期。回执有效期为 7 天,过期后不再支持已读操作
UNKNOWN—未知状态,请联系 ZEGO 技术支持

回执状态流转示意图
会话与消息类型
消息、会话类型是否支持说明
单聊会话✅支持消息已读与会话已读两种方式
群组会话✅支持消息已读;会话已读不支持群聊;群聊可查询已读 / 未读 / 已送达成员列表
房间会话❌暂不支持发送房间会话的消息回执
普通消息 / 富媒体消息 / 自定义消息 / 合并消息✅均可携带回执
信令消息 / 弹幕消息等❌不在回执支持的消息类型范围内,需业务侧另行实现"已读"语义

已读方式与查询

对已接收的回执消息,可通过以下两种方式标记已读:

方式接口语义与限制
消息已读sendMessageReceiptsRead把一批指定消息置为已读。单次消息列表不超过 10 条;仅支持回执状态为 PROCESSING 的已接收消息;不允许跨会话
会话已读sendConversationMessageReceiptRead把指定会话内所有已接收的对方消息置为已读。仅单聊支持;只作用于"设置已读之前"获取的消息;建议在从会话列表进入会话时使用

不建议在同一会话中混用两种已读接口。接入前先确定已读方式:按会话进入时机整体清未读 → 会话已读(单聊);按消息粒度精确控制 → 消息已读。会话已读无需在会话内反复调用。

此外,SDK 提供以下回执查询能力:

接口用途与注意事项
queryMessageReceiptsInfo批量查询消息的回执状态、已读用户数、未读用户数。查询他人发送的消息时,已读与未读用户数均为 0
queryGroupMessageReceiptMemberList查询群消息的已读、未读(未送达)、或已送达状态的成员列表(3.1.0+,通过 filterType 区分;count 每页最多 100 且必须大于 0)
queryGroupMessageReceiptReadMemberList / queryGroupMessageReceiptUnreadMemberList3.1.0 起废弃,请改用 queryGroupMessageReceiptMemberList
ZIMMessageReceiptInfo.readTime获取回执已读时间(2.22.0+),可用于阅后即焚等密聊场景。发送者侧需会话内成员全部已读才有值;接收者侧为调用消息已读成功时的服务端时间戳;不支持"会话已读"

如需对会话的历史消息进行回执相关操作,需先完成查询历史消息、判断历史消息的回执状态后再处理。

已送达状态

注意

需要已送达状态功能,请使用 3.1.0 及以上版本的 SDK 。

场景流转为"已送达"的触发条件
单聊① 接收端在线收到消息后,SDK 自动确认;② 接收端收到离线推送后调用服务端 API 确认;③ 无离线推送时,本端上线拉取到消息后 SDK 自动确认
群聊当所有群成员都已送达且仍有成员未读时,回执状态流转为"已送达"

离线推送送达 ≠ 消息送达。必须 ZIM message 实际送达到接收端,或通过服务端 API 确认,才会流转为"已送达"。若需在接收方收到离线推送后即让发送端看到"已送达"(iOS 可开启推送拦截,Android FCM 可使用 DataMessage 推送类型,国内 Android 厂商暂不支持),可在收到推送后调用服务端 API 进行确认。

单聊回执三态链路(含离线场景)

接入示例

// 用户 A 发送一条带回执的消息(以单聊文本消息为例)
final message = ZIMTextMessage(message: 'test');
final sendConfig = ZIMMessageSendConfig()..hasReceipt = true;   // 必须为 true,否则该消息不进入回执链路
ZIM.getInstance()!.sendMessage(message, conversationID, ZIMConversationType.peer, sendConfig);

// 发送端监听回执变化(含已送达 / 已读 / 已过期)
ZIMEventHandler.onMessageReceiptChanged = (zim, infos) {
  for (final info in infos) {
    switch (info.status) {
      case ZIMMessageReceiptStatus.delivered: renderDelivered(info.messageID); break;   // 已送达(3.1.0+)
      case ZIMMessageReceiptStatus.done:      renderRead(info.messageID); break;        // 已读
      case ZIMMessageReceiptStatus.expired:   renderExpired(info.messageID); break;     // 已过期,回执标识置灰
      default: break;
    }
  }
};
ZIMEventHandler.onConversationMessageReceiptChanged = (zim, infos) {
  // 对方设置了会话的已读回执(仅单聊)
};

// 用户 B 执行已读——方式一:消息已读(单次不超过 10 条,仅对 PROCESSING 状态消息有效)
final pendingList = receivedList
    .where((m) => m.receiptStatus == ZIMMessageReceiptStatus.processing)
    .take(10)
    .toList();
ZIM.getInstance()!.sendMessageReceiptsRead(pendingList, conversationID, ZIMConversationType.peer);

// 方式二:会话已读(仅单聊,建议在从会话列表进入会话时调用)
ZIM.getInstance()!.sendConversationMessageReceiptRead(conversationID, ZIMConversationType.peer);

// (可选)查询一批消息的回执状态、已读用户数和未读用户数
ZIM.getInstance()!.queryMessageReceiptsInfo(messages, conversationID, ZIMConversationType.peer)
    .then((res) {
  // res.infos:回执信息列表;res.errorMessageIDs:查询失败的消息 ID 列表
});

// (可选)查询群消息的已读 / 未读成员列表(仅自己发送的消息)
final queryConfig = ZIMGroupMessageReceiptMemberQueryConfig()
  ..nextFlag = 0   // 初始填 0,后续填回调返回的 flag
  ..count = 10;
ZIM.getInstance()!.queryGroupMessageReceiptReadMemberList(message, groupID, queryConfig)
    .then((res) {
  // res.userList:已读成员列表;res.nextFlag:下一页 flag
});

常见问题

先查三件事——消息发送时 hasReceipt 是否为 true;消息的 receiptStatus 是否为 PROCESSING(只有该状态才能被设为已读);发送端与接收端是否在同一会话内(不允许跨会话)。

常见原因有两个——SDK 版本低于 3.1.0 或"已送达"能力未开通(需联系 ZEGO 技术支持开启);接收端处于离线且未接入服务端上报。注意离线推送送达本身不等于消息送达。

不能。会话已读仅支持单聊。群聊只能走消息已读,或通过群成员列表能力展示"谁已读"。群聊里"已送达"的流转条件是所有群成员都已送达且仍有成员未读。

回执有效期为 7 天,超期会流转为"已过期",且不再支持已读操作。建议 UI 层对过期回执做置灰或移除处理。

可以。自定义消息与文本、图片、文件、音频、视频等消息一样可携带回执,合并消息同样支持;只有信令消息、弹幕消息不支持(需业务侧另行实现"已读"语义)。

发送者侧需会话内成员全部已读才有值,为最后一个成员已读时的服务端时间戳;接收者侧为调用消息已读成功时的服务端时间戳;两条都为 0 表示尚未满足条件。readTime 不支持"会话已读",自 2.22.0 起支持。

2026-10-10

上一篇

消息重发

下一篇

处理呼叫失败

当前页

返回到顶部