主题
事件与回调
本页是接入规则和完整事件速查表。需要逐个回调查看载荷字段、准确触发条件、 可靠性、关联 API 和页面处理代码时,进入 回调详细说明;全部公开方法的调用代码见 100 个 API 示例。
1. 订阅入口
events.subscribe
| 平台 | 入口 | 取消订阅 |
|---|---|---|
| iOS | client.addEventListener { event in ... } | XHIMEventListenerToken.cancel() 或释放 token |
| macOS | client.addEventListener { event in ... } | XHIMEventListenerToken.cancel() 或释放 token |
| Android | client.events.collect { event -> ... } | 取消收集它的 Coroutine |
| Windows | await foreach (var evt in client.Events(token)) | 取消 CancellationToken |
| HarmonyOS | const 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-query2. 完整事件表
| 统一事件 | 载荷 | 何时产生 | 接入方动作 |
|---|---|---|---|
stateChanged | XHIMClientState | 生命周期变化 | 更新连接提示;到 ready 再允许写操作 |
messageQueued | 消息接受回执 payload | 本地 Outbox 接受新消息 | 按 client message ID 重查消息 |
messageRetryQueued | 回执 payload | 失败消息重新入队 | 重查消息状态 |
messageCancelled | 回执 payload | 待发送消息被取消 | 重查消息状态 |
conversationReadChanged | conversationID | 已读水位改变 | 重查会话和总未读 |
messageMutated | clientMessageID | 编辑或撤回完成 | 重查目标消息 |
mediaTaskUpdated | XHIMMediaTaskUpdate | 媒体任务状态变化 | 以 task ID 查询完整任务 |
messageUpserted | XHIMProjectionChange | 消息投影新增/替换 | 重查对应会话时间线 |
messageStateChanged | XHIMProjectionChange | 消息投递状态变化 | 重查对应消息 |
conversationChanged | XHIMProjectionChange | 会话摘要、未读、偏好改变 | 重查会话页 |
socialChanged | XHIMProjectionChange | 好友/群组/黑名单投影改变 | 按 socialScope 重查 |
syncApplied | XHIMProjectionChange | 一批远端同步完成 | 刷新当前页面依赖的投影 |
presenceChanged | XHIMPresenceUpdate | 用户在线状态变化 | 显示并按 expiresAt 本地过期 |
typingChanged | XHIMTypingUpdate | 会话输入状态变化 | 显示并按 expiresAt 本地过期 |
projectionInvalidated | XHIMProjectionChange | 遇到未来 schema / kind | 完整重查相关页面,不解析未知值 |
平台类型名称:
| 统一事件 | iOS | macOS | Android | Windows | HarmonyOS |
|---|---|---|---|---|---|
| state | .stateChanged | .stateChanged | XHIMEvent.StateChanged | XHIMEvent.StateChanged | XHIMStateChangedEvent |
| queued | .messageQueued | .messageQueued | XHIMEvent.MessageQueued | XHIMEvent.MessageQueued | XHIMMessageQueuedEvent |
| retry queued | .messageRetryQueued | .messageRetryQueued | XHIMEvent.MessageRetryQueued | XHIMEvent.MessageRetryQueued | XHIMMessageRetryQueuedEvent |
| cancelled | .messageCancelled | .messageCancelled | XHIMEvent.MessageCancelled | XHIMEvent.MessageCancelled | XHIMMessageCancelledEvent |
| read | .conversationReadChanged | .conversationReadChanged | XHIMEvent.ConversationReadChanged | XHIMEvent.ConversationReadChanged | XHIMConversationReadChangedEvent |
| mutated | .messageMutated | .messageMutated | XHIMEvent.MessageMutated | XHIMEvent.MessageMutated | XHIMMessageMutatedEvent |
| media | .mediaTaskUpdated | .mediaTaskUpdated | XHIMEvent.MediaTaskUpdated | XHIMEvent.MediaTaskUpdated | XHIMMediaTaskUpdatedEvent |
| message upsert | .messageUpserted | .messageUpserted | XHIMEvent.MessageUpserted | XHIMEvent.MessageUpserted | XHIMMessageUpsertedEvent |
| message state | .messageStateChanged | .messageStateChanged | XHIMEvent.MessageStateChanged | XHIMEvent.MessageStateChanged | XHIMMessageStateChangedEvent |
| conversation | .conversationChanged | .conversationChanged | XHIMEvent.ConversationChanged | XHIMEvent.ConversationChanged | XHIMConversationChangedEvent |
| social | .socialChanged | .socialChanged | XHIMEvent.SocialChanged | XHIMEvent.SocialChanged | XHIMSocialChangedEvent |
| sync | .syncApplied | .syncApplied | XHIMEvent.SyncApplied | XHIMEvent.SyncApplied | XHIMSyncAppliedEvent |
| presence | .presenceChanged | .presenceChanged | XHIMEvent.PresenceChanged | XHIMEvent.PresenceChanged | XHIMPresenceChangedEvent |
| typing | .typingChanged | .typingChanged | XHIMEvent.TypingChanged | XHIMEvent.TypingChanged | XHIMTypingChangedEvent |
| invalidated | .projectionInvalidated | .projectionInvalidated | XHIMEvent.ProjectionInvalidated | XHIMEvent.ProjectionInvalidated | XHIMProjectionInvalidatedEvent |
3. Projection change 字段
XHIMProjectionChange 是轻量失效通知,不是完整业务对象:
| 字段 | 用途 |
|---|---|
schemaVersion | 事件结构版本 |
kind / nativeKind | 已知类型与未修改原始值 |
origin / nativeOrigin | local、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或@MainActorViewModel; - 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
→ readyProvider 失败时保留原始稳定错误。UI 只根据 userAction 决定显示“重试登录” 或回到 App 登录页,不记录凭证文本。