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

消息转发

2026-10-10

功能简介

消息转发是即时通讯的高频基础能力,包含两种转发方式:

  • 逐条转发:将一条或多条消息直接转发到目标会话。
  • 合并转发:将多条消息打包为一条合并消息转发到目标会话,接收方点击可查看子消息。

消息转发支持单聊、群聊两种会话方式。逐条转发需要 ZIM SDK 2.0.0 及以上版本,合并转发需要 ZIM SDK 2.14.0 及以上版本。

消息转发效果展示:

场景预期表现
逐条转发 50 条消息全部成功,无限频报错(间隔 150ms 调度)
转发列表含发送失败的消息失败消息被跳过 / 报错,其余正常转发
合并转发 12 条消息接收方收到 1 条合并消息,点开可见 12 条子消息
接收端 SDK 2.0~2.14可收到合并消息,类型为未知,需业务降级处理
合并列表含信令 / 弹幕发送被拒绝或按文档过滤
转发后的消息排序新消息按送达时间排至目标会话末尾
合并消息携带消息回执回执链路正常流转

实现方案

逐条转发

逐条转发的本质是 “复用原消息对象再次发送” :通过 queryHistoryMessage 获取原消息对象后传入 sendMessage,原消息对象中的富媒体消息(图片、文件、音频、视频)逐条转发时复用原消息的富媒体 URL(引用原文件),不会重新上传,也不额外占用一份富媒体存储。

注意

发送限频:文本等普通消息单客户端限频 10 次/秒(间隔 100ms),批量转发时若不加控制会触发限频导致部分消息失败,推荐每条间隔 150ms(在 100ms 之上留出余量),并采用"间隔调度 + 失败重试"策略。

合并转发

合并转发是将多条消息打包为一条合并消息进行转发,合并消息具有以下特点:

  • 合并消息支持嵌套,合并消息内可包含其他合并消息,可逐层调用 queryCombineMessageDetail 拉取。
  • 合并消息的消息大小无限制,但是超大合并消息建议在产品层进行拆分,确保客户端展开消息时的渲染性能与消息查看体验。
  • 合并消息不支持合并信令、弹幕、撤回、系统类型的消息,也不支持合并发送失败的消息,构造合并消息前需要对这些消息进行过滤。
  • 合并消息支持携带消息回执,转发内容的已读链路不会在合并消息处中断。
注意
  • 合并消息的标题 title 默认最大 20 字节、概要 summary 默认最大 100 字节,如需调整请联系 ZEGO 技术支持。
  • 接收端 SDK 的版本在 [2.0.0, 2.14.0) 区间可收到合并消息,但类型显示为未知、无法获取内容;1.x 版本的 SDK 无法接收合并消息。

转发后的消息语义

  • 转发产生的是一条全新消息:新的消息 ID、新的时间戳,与原消息再无关联;如需"引用原文"语义,请使用消息回复(reply)能力。
  • 排序按目标会话的送达时间排至末尾,不保留原消息的发送时序。
  • 不继承原消息的已读 / 未读状态与回执状态,新消息的回执按目标会话重新计算。
  • 原消息被撤回或删除,不影响已转发出去的消息;合并转发产物是独立消息,原消息后续被撤回 / 删除同样不影响子消息展示。

接入最佳实践

  • 转发前校验:合并转发前过滤不支持的消息类型(信令 / 弹幕 / 撤回 / 系统 / 发送失败的消息),避免发送报错。
  • 限频调度:逐条转发务必控制调用间隔(推荐 150ms),批量转发用"间隔调度 + 失败重试",不要连续裸调 sendMessage。
  • 失败重试:单条转发失败应记录失败列表并支持重试,避免用户感知"转发的消息少了"。
  • 版本兼容提示:合并消息接收端需 ≥ 2.14.0 才能正常查看内容,业务侧应对低版本端做降级提示。
  • 接收端按需拉取:接收回调只带标题 / 概要 / 合并 ID,子消息内容必须经 queryCombineMessageDetail 拉取;嵌套合并需逐层多次拉取。
  • 大批量转发优先合并:合并转发将多条消息打包为一条消息传输,大批量场景优先使用;合并消息体大小无限制,但超大合并在产品层拆分。

接入示例

// 1. 从历史消息中获取待转发消息(分页示例)
final queryConfig = ZIMMessageQueryConfig()
  ..nextMessage = null    // 首次获取传 null,后续传上一页最后一条
  ..count = 30
  ..reverse = true;
final queried = await ZIM.getInstance()!
    .queryHistoryMessage(conversationID, ZIMConversationType.peer, queryConfig);
final messageList = queried.messageList;

// 2. 逐条转发:复用原消息对象再次发送,每条间隔 ≥150ms,避免触发 100ms 限频
Future<void> forwardOneByOne(List<ZIMMessage> list, String toConversationID,
    ZIMConversationType conversationType, ZIMMessageSendConfig config) async {
  for (final msg in list) {
    try {
      await ZIM.getInstance()!.sendMessage(msg, toConversationID, conversationType, config);
      await Future<void>.delayed(const Duration(milliseconds: 150));   // 推荐间隔 150ms
    } catch (e) {
      // 单条失败:记录并继续,最后统一汇总失败列表供重试
    }
  }
}

// 3. 合并转发:构造合并消息体(发送与查看需 2.14.0+)
final combineMessage = ZIMCombineMessage(
  title: '聊天记录',
  summary: '共 ${messageList.length} 条消息',
  messageList: messageList,
);
ZIM.getInstance()!.sendMessage(combineMessage, toConversationID, conversationType, config);

// 4. 接收方查看合并消息详情(回调只返回标题、概要、合并 ID)
ZIMEventHandler.onMessageReceived = (zim, result) {
  for (final msg in result.messageList) {
    if (msg.type == ZIMMessageType.combine) {
      ZIM.getInstance()!.queryCombineMessageDetail(msg as ZIMCombineMessage).then((res) {
        // 子消息在 res.message.messageList 中;嵌套合并需再次调用本接口逐层拉取
      });
    }
  }
};

常见问题

会。转发本质是重新发送,生成新的消息 ID 与时间戳,原消息保持不变。转发消息无法与原文建立自动关联,如需"引用原文"语义,请使用消息回复(reply)能力。

在。转发产生的是独立的新消息,原消息撤回不影响已转发的消息;合并转发同理,子消息展示不受影响。

可以。通过 queryCombineMessageDetail 获取子消息对象后,可将其作为普通消息再次逐条转发。

合并消息(type = 100)消息大小无限制。但超大合并(如数百条)仍建议在产品层拆分,兼顾接收端展开性能与 queryCombineMessageDetail 查询体验。

最常见原因是连续调用 sendMessage 触发了 100ms 限频。请改为间隔调度(推荐 150ms),并增加失败重试。

能。合并消息支持携带回执,发送合并消息时可按需设置 hasReceipt,转发内容的「已读」链路不会在合并消息处中断。

不会。逐条转发复用原消息的富媒体 URL(引用原文件),不重新上传、不额外占用一份富媒体存储。

2026-10-10

上一篇

实现 “正在输入” 状态提示

下一篇

消息重发

当前页

返回到顶部