Skip to content

消息与会话 API

1. 消息发送与状态

api-id用途主要输入返回
message.send_text发送文字conversationID, 可选 clientMessageID, textXHIMSendReceipt
message.send_custom发送任意标准/自定义消息conversationID, 可选 clientMessageID, XHIMOutgoingMessageXHIMSendReceipt
message.retry重试一条失败的 Outbox 消息clientMessageIDXHIMSendReceipt
message.cancel取消一条尚未被服务端接受的消息clientMessageIDXHIMSendReceipt

sendTexttext/plain@1 的便利接口。其他类型统一通过 XHIMOutgoingMessage

字段约束
contentType稳定命名空间,例如 com.customer.order.card
contentVersion该类型自己的正整数版本
payload不可变二进制载荷;不能放本地路径或临时下载 URL
fallbackText旧客户端、通知和会话预览可安全显示的文本

成功返回表示消息意图已被本地可靠 Outbox 接受,不等于对方已经收到。最终状态 从消息查询结果的 statemessageStateChanged 事件判断。

clientMessageID 省略时由 SDK 生成。业务需要跨进程幂等重试时,应自行生成 UUID,并在每次重试中复用同一个值。

2. 编辑、撤回和仅自己删除

api-id用途主要输入返回
message.edit_text编辑文字消息conversationID, serverMessageID, mutationID, expectedRevision, text更新后的 XHIMMessage
message.recall撤回消息conversationID, serverMessageID, mutationID, expectedRevision更新后的 XHIMMessage
message.delete_for_self仅当前账号删除conversationID, serverMessageID, mutationID, expectedRevisionXHIMMessageVisibilityMutation

expectedRevision == 0 表示创建型/未指定 CAS 基线,其他值表示只在服务端当前 revision 与之相等时执行。发生并发冲突时重新查询目标消息或可见性,再让用户 决定是否重试;不要自动不断增加条件绕过冲突。

编辑和撤回会保留稳定消息身份,mutationKind 分别变为 editTextrecall。业务 UI 应根据模型显示“已编辑”或“已撤回”,不要自行删除时间线项。

3. 单条、分页和搜索

api-id用途主要输入返回
message.get按客户端消息 ID 获取单条clientMessageIDXHIMMessage
message.list读取本地会话消息页conversationID, 可选 cursor, limitXHIMMessagePage
message.history按服务端序号读取历史conversationID, 可选 continuation, limitXHIMMessageHistoryPage
message.search搜索本地消息投影XHIMMessageSearchQuery, 可选 cursor, limitXHIMMessagePage

messages 用于常规本地时间线和游标翻页。getMessageHistory 使用稳定服务端 序号 continuation,适合清空/隐藏视图规则和历史回溯。两种 continuation 都是 SDK 所有,不允许用页码或时间戳代替。

XHIMMessageSearchQuery 可按文本、会话、发送者、内容类型和时间范围组合过滤。 搜索结果仍是 XHIMMessage,未知自定义类型也保留原 payload 与 fallback。

分页通用规则:

  • 首次调用传空 cursor / continuation;
  • nextCursorcontinuation 为空表示结束;
  • cursor 只在同一账号、同一查询条件下复用;
  • 收到投影变更后刷新第一页,不能假定旧 cursor 是实时订阅;
  • limit 必须处于各 Facade 声明的范围,推荐聊天页 50、会话页 50。

4. 会话列表与单聊

api-id用途主要输入返回
conversation.list读取本地会话页可选 cursor, limitXHIMConversationPage
conversation.direct获取或创建稳定单聊会话peerUserIDXHIMDirectConversation
conversation.clear为当前账号清空到指定序号conversationID, throughServerSequence, mutationID, expectedRevisionXHIMConversationViewMutation
conversation.hide隐藏会话当前视图conversationID, mutationID, expectedRevisionXHIMConversationViewMutation

请优先用 directConversation(peerUserID) 获取单聊 ID,不要在客户端拼接 alice_bob。服务端返回的 participant 和 conversation ID 才是跨端合同。

清空和隐藏是当前账号的 Server-authoritative 视图操作,不会替其他成员删除 消息。clearConversationthroughServerSequence 必须来自已查询消息或会话 高水位。

5. 已读、未读和对端已读

api-id用途主要输入返回
conversation.mark_read提交一个会话的已读水位conversationID, throughServerSequenceXHIMConversationReadReceipt
conversation.mark_all_read幂等标记全部会话已读mutationID, maxChangedReadsXHIMMarkAllConversationsReadResult
conversation.total_unread查询本地总未读64 位整数
conversation.peer_reads查询成员已读投影conversationID, limitXHIMConversationPeerReadPage

已读水位只前进不后退。聊天页进入前台并确定用户确实看见消息后,再提交当前 最大 serverSequence。收到 conversationReadChangedconversationChanged 后重查会话,而不是在 UI 中直接对未读数做加减。

markAllConversationsRead 的结果可能因保护上限只带一部分 changedReads; changedReadsTruncated == truelocalProjectionComplete == false 时刷新整个 会话列表。

6. 会话偏好与本地草稿

api-id用途主要输入返回
conversation.set_preference原子修改置顶和免打扰conversationID, isPinned, notificationsMuted, mutationID, expectedRevisionXHIMConversationPreference
conversation.set_draft保存账号隔离本地草稿conversationID, XHIMOutgoingMessageXHIMConversationDraft
conversation.get_draft读取草稿conversationIDXHIMConversationDraft
conversation.clear_draft清除草稿conversationIDXHIMConversationDraft

偏好是可同步的服务端状态,使用 mutation ID 和 revision。草稿是本机、当前账号 的本地状态,不上传、不产生聊天消息,也不要把密码、Token 或支付敏感信息放入 草稿 payload。

7. 典型聊天页

swift
eventToken = client.addEventListener { [weak self] event in
    switch event {
    case .messageUpserted(let change),
         .messageStateChanged(let change):
        if change.conversationID == conversationID {
            self?.reloadFirstPage()
        }
    default:
        break
    }
}

client.messages(
    conversationID: conversationID,
    limit: 50,
    onSuccess: { page in
        self.messages = page.messages
    },
    onFailure: { error in
        self.showError(error.message)
    }
)

client.sendText(
    conversationID: conversationID,
    text: composer.text,
    onSuccess: { _ in
        composer.clear()
    },
    onFailure: { error in
        self.showError(error.message)
    }
)

页面销毁时取消监听 token,但不要因为一个页面消失就关闭账号级 Client。 事件的完整平台写法和线程要求见事件与回调

XHIM 客户端 SDK 与服务端文档