Skip to content

事件与回调

本页是接入规则和完整事件速查表。需要逐个回调查看载荷字段、准确触发条件、 可靠性、关联 API 和页面处理代码时,进入 回调详细说明;全部公开方法的调用代码见 100 个 API 示例

1. 订阅入口

events.subscribe

平台入口取消订阅
iOSclient.addEventListener { event in ... }XHIMEventListenerToken.cancel() 或释放 token
macOSclient.addEventListener { event in ... }XHIMEventListenerToken.cancel() 或释放 token
Androidclient.events.collect { event -> ... }取消收集它的 Coroutine
Windowsawait foreach (var evt in client.Events(token))取消 CancellationToken
HarmonyOSconst off = client.onEvent(listener)调用返回的 off()

iOS、macOS 和 Windows 还提供只包含 durable projection invalidation 的 projectionEvents / ProjectionEvents()。Android 和 HarmonyOS 从统一 XHIMEvent 流筛选对应类型。

iOS 与 macOS 回调都在 MainActor 上按事件顺序执行:

swift
private var eventToken: XHIMEventListenerToken?

eventToken = client.addEventListener { [weak self] event in
    if case .conversationChanged = event {
        self?.reloadConversations()
    }
}

Swift Concurrency 项目仍可使用 for await event in client.events,取消消费 Task 即退订。

应当先订阅,再执行首次查询,避免订阅与首屏查询之间出现窗口:

text
install subscriber → query initial page → consume events → re-query

2. 完整事件表

统一事件载荷何时产生接入方动作
stateChangedXHIMClientState生命周期变化更新连接提示;到 ready 再允许写操作
messageQueued消息接受回执 payload本地 Outbox 接受新消息按 client message ID 重查消息
messageRetryQueued回执 payload失败消息重新入队重查消息状态
messageCancelled回执 payload待发送消息被取消重查消息状态
conversationReadChangedconversationID已读水位改变重查会话和总未读
messageMutatedclientMessageID编辑或撤回完成重查目标消息
mediaTaskUpdatedXHIMMediaTaskUpdate媒体任务状态变化以 task ID 查询完整任务
messageUpsertedXHIMProjectionChange消息投影新增/替换重查对应会话时间线
messageStateChangedXHIMProjectionChange消息投递状态变化重查对应消息
conversationChangedXHIMProjectionChange会话摘要、未读、偏好改变重查会话页
socialChangedXHIMProjectionChange好友/群组/黑名单投影改变socialScope 重查
syncAppliedXHIMProjectionChange一批远端同步完成刷新当前页面依赖的投影
presenceChangedXHIMPresenceUpdate用户在线状态变化显示并按 expiresAt 本地过期
typingChangedXHIMTypingUpdate会话输入状态变化显示并按 expiresAt 本地过期
projectionInvalidatedXHIMProjectionChange遇到未来 schema / kind完整重查相关页面,不解析未知值

平台类型名称:

统一事件iOSmacOSAndroidWindowsHarmonyOS
state.stateChanged.stateChangedXHIMEvent.StateChangedXHIMEvent.StateChangedXHIMStateChangedEvent
queued.messageQueued.messageQueuedXHIMEvent.MessageQueuedXHIMEvent.MessageQueuedXHIMMessageQueuedEvent
retry queued.messageRetryQueued.messageRetryQueuedXHIMEvent.MessageRetryQueuedXHIMEvent.MessageRetryQueuedXHIMMessageRetryQueuedEvent
cancelled.messageCancelled.messageCancelledXHIMEvent.MessageCancelledXHIMEvent.MessageCancelledXHIMMessageCancelledEvent
read.conversationReadChanged.conversationReadChangedXHIMEvent.ConversationReadChangedXHIMEvent.ConversationReadChangedXHIMConversationReadChangedEvent
mutated.messageMutated.messageMutatedXHIMEvent.MessageMutatedXHIMEvent.MessageMutatedXHIMMessageMutatedEvent
media.mediaTaskUpdated.mediaTaskUpdatedXHIMEvent.MediaTaskUpdatedXHIMEvent.MediaTaskUpdatedXHIMMediaTaskUpdatedEvent
message upsert.messageUpserted.messageUpsertedXHIMEvent.MessageUpsertedXHIMEvent.MessageUpsertedXHIMMessageUpsertedEvent
message state.messageStateChanged.messageStateChangedXHIMEvent.MessageStateChangedXHIMEvent.MessageStateChangedXHIMMessageStateChangedEvent
conversation.conversationChanged.conversationChangedXHIMEvent.ConversationChangedXHIMEvent.ConversationChangedXHIMConversationChangedEvent
social.socialChanged.socialChangedXHIMEvent.SocialChangedXHIMEvent.SocialChangedXHIMSocialChangedEvent
sync.syncApplied.syncAppliedXHIMEvent.SyncAppliedXHIMEvent.SyncAppliedXHIMSyncAppliedEvent
presence.presenceChanged.presenceChangedXHIMEvent.PresenceChangedXHIMEvent.PresenceChangedXHIMPresenceChangedEvent
typing.typingChanged.typingChangedXHIMEvent.TypingChangedXHIMEvent.TypingChangedXHIMTypingChangedEvent
invalidated.projectionInvalidated.projectionInvalidatedXHIMEvent.ProjectionInvalidatedXHIMEvent.ProjectionInvalidatedXHIMProjectionInvalidatedEvent

3. Projection change 字段

XHIMProjectionChange 是轻量失效通知,不是完整业务对象:

字段用途
schemaVersion事件结构版本
kind / nativeKind已知类型与未修改原始值
origin / nativeOriginlocal、remoteSync、outbox、未来值
socialScope好友申请、好友、群、群成员、黑名单、入群申请
messageState消息状态变更时的已知状态
accountEpoch区分登录账号生命周期
connectionGeneration区分重连代次
projectionRevision每 Client 单调失效序号;跳号意味着重查
entityRevision相关实体 revision
sequence消息/同步服务端序号
affectedCount批量变更影响数量
各种 ID缩小重查范围;空值表示需要扩大刷新

只要 requiresFullRequery 为 true、revision 不连续或 scope 为空,就重新查询 当前页面依赖的完整投影。不要尝试回放事件补数据库。

4. UI 线程规则

原生 Core 在 XHIM 私有串行 callback 线程产生 Completion 和 Event。各 Facade 会先复制 native borrowed bytes,再恢复平台异步调用;但恢复位置不保证是 UI 线程。

  • iOS/macOS:回调式 Facade 已切到 MainActor;直接消费 AsyncStream 时使用 await MainActor.run@MainActor ViewModel;
  • Android:在 ViewModel Scope 中收集,写 UI state 时使用 Main dispatcher;
  • Windows:根据 UI 框架切回 Dispatcher;
  • HarmonyOS:在 UIAbility/组件允许的任务上下文更新状态。

Callback 中可以提交新的异步请求,但不能同步阻塞等待另一个 XHIM callback。

5. 普通请求取消

普通请求取消只取消一次异步操作的等待/执行许可,不撤销已经提交的服务端业务 事实:

swift
let request = client.searchMessages(
    query,
    limit: 50,
    onSuccess: { page in self.show(page.messages) },
    onFailure: { error in self.show(error.message) }
)
request.cancel()

Swift Concurrency 调用则取消承载请求的 Task

kotlin
val job = scope.launch { client.searchMessages(query, limit = 50) }
job.cancel()
csharp
using var cts = new CancellationTokenSource();
var task = client.SearchMessagesAsync(query, limit: 50, cts.Token);
cts.Cancel();
ts
let requestId: bigint = 0n
const pending = client.searchMessages(query, undefined, 50,
  (id: bigint) => requestId = id)
client.cancelRequest(requestId)
await pending

取消结果使用稳定 CANCELLED 错误。已经由 Outbox 接受的消息要用 cancelMessage;持久化媒体任务要用 cancelMediaTask

6. 自动续凭回调

credentialRequired 不单独暴露给页面做 Token 逻辑。一键 connect 安装的 Business Provider 会在账号容器内自动处理:

text
state credentialRequired
  → SDK 合并并发刷新
  → 调用业务 Provider
  → updateCredential
  → reconnect + sync
  → ready

Provider 失败时保留原始稳定错误。UI 只根据 userAction 决定显示“重试登录” 或回到 App 登录页,不记录凭证文本。

XHIM 客户端 SDK 与服务端文档