Skip to content

macOS 回调式 API

适用版本:0.1 Commercial Beta 适用模块:XHIM 最低版本:macOS 12、Swift 5.9

本页是 macOS 原生开发者的回调 API 入口。所有 onSuccess/onFailure 和事件 回调都在 MainActor 串行执行,可以直接更新 AppKit 或 SwiftUI 状态。macOS 与 iOS 复用 Swift 类型,但本页只说明 macOS 的安装后调用、窗口/进程生命周期、 Sandbox 和文件访问行为。

默认 Completion Facade 覆盖全部公开异步/抛错入口;页面代码不需要 为 SDK 调用展开 Taskdo-catch。Swift Concurrency 同名重载仅作为 Repository、批处理和高级并发项目的可选入口。

1. 连接并登录

swift
XHIMClient.connect(
    server:userID:appID:authentication:storageRootURL:
    onConnecting:onConnectSuccess:onConnectFailure:
) -> XHIMRequest
swift
private var client: XHIMClient?
private var connectRequest: XHIMRequest?

connectRequest = XHIMClient.connect(
    server: "https://im-test.example.com",
    userID: "alice",
    onConnecting: {
        print("XHIM macOS connecting")
    },
    onConnectSuccess: { [weak self] client in
        self?.client = client
    },
    onConnectFailure: { error in
        print(error.stableCode, error.message)
    }
)

Production 把宿主已有账号会话转换为 SDK 凭证 Provider。Window 和 ViewController 不接触短期凭证:

swift
connectRequest = XHIMClient.connect(
    server: "https://im.example.com",
    userID: account.userID,
    authentication: .business(AccountService.shared.xhimCredential),
    onConnecting: {},
    onConnectSuccess: { [weak self] in self?.client = $0 },
    onConnectFailure: { [weak self] in self?.show($0.message) }
)
参数类型说明
serverStringXHIM Server HTTPS 基地址
userIDString当前业务用户 ID
appIDString?单租户部署通常省略
authenticationXHIMAuthenticationDevelopment 或业务凭证 Provider
storageRootURLURL?通常省略;默认写入 Application Support 的账号隔离目录

2. 事件监听

swift
private var eventToken: XHIMEventListenerToken?

eventToken = client.addEventListener { [weak self] event in
    switch event {
    case .stateChanged(let state):
        self?.renderConnection(state)
    case .messageUpserted(let change),
         .messageStateChanged(let change):
        self?.reloadMessages(conversationID: change.conversationID)
    case .conversationChanged:
        self?.reloadConversations()
    case .presenceChanged(let update):
        self?.renderPresence(update)
    case .typingChanged(let update):
        self?.renderTyping(update)
    case .customSignalReceived(let event):
        self?.handleOnlineCollaborationSignal(event.signal)
    default:
        break
    }
}

XHIMEventListenerToken 必须由账号 Session 持有,不能只存在局部变量。多窗口 共享一个 Client,可以各自安装监听并在窗口释放时取消自己的 token。

customSignalReceived 只用于光标、协作选择区、白板指针等在线瞬时状态;它不 进入 SQLite、Outbox 或 Sync,超时/离线允许丢失。需要离线补发和历史审计时应 改用版本化自定义消息。

3. 单聊与文字消息

swift
client.directConversation(
    with: "bob",
    onSuccess: { [weak self] conversation in
        self?.client?.sendText(
            conversationID: conversation.conversationID,
            text: "Hello from macOS",
            onSuccess: { _ in print("message queued") },
            onFailure: { print($0.stableCode, $0.message) }
        )
    },
    onFailure: { print($0.stableCode, $0.message) }
)

sendText 成功表示消息进入可靠 Outbox,不表示对端已读。页面通过 messageStateChanged 后重查消息,通过已读事件后重查会话/同伴已读。

4. 会话和消息分页

swift
client.conversations(
    limit: 50,
    onSuccess: { [weak self] in self?.conversations = $0.conversations },
    onFailure: { print($0.stableCode, $0.message) }
)

client.messages(
    conversationID: conversationID,
    limit: 50,
    onSuccess: { [weak self] in self?.messages = $0.messages },
    onFailure: { print($0.stableCode, $0.message) }
)

分页 Cursor 是不透明 Data,只能原样传回同一查询。不要从 SQLite 自己拼会话 或未读数。

群聊窗口的已读上报和读者列表使用同一回调 Facade:

swift
client.markGroupMessagesRead(
    conversationID: groupConversationID,
    serverMessageIDs: visibleServerMessageIDs,
    onSuccess: { _ in self.reloadConversation() },
    onFailure: { self.showError($0.message) }
)
client.groupMessageReaders(
    conversationID: groupConversationID,
    serverMessageIDs: [serverMessageID],
    onSuccess: { self.readerPage = $0 },
    onFailure: { self.showError($0.message) }
)

两个方法只消费本地已同步的服务端消息 ID,不会在 AppKit 层建第二份 逐消息已读状态。

5. 自定义消息

swift
let message = XHIMOutgoingMessage(
    contentType: "com.example.order.card",
    contentVersion: 1,
    payload: Data(#"{"orderID":"20260728001"}"#.utf8),
    fallbackText: "[订单] 20260728001"
)

client.sendMessage(
    conversationID: conversationID,
    message: message,
    onSuccess: { _ in print("custom message queued") },
    onFailure: { print($0.stableCode, $0.message) }
)

未知 contentType 必须显示 fallbackText。Renderer 只负责展示,不改变协议 payload。

Presence 和 Typing 快照

swift
presenceRequest = client.subscribePresence(
    userIDs: visibleMemberIDs,
    onSuccess: { [weak self] snapshots in
        self?.outlineView.reloadPresence(snapshots)
    },
    onFailure: { [weak self] error in
        self?.presentError(error)
    }
)

typingRequest = client.queryTyping(
    conversationID: conversationID,
    userID: peerUserID,
    onSuccess: { [weak self] snapshot in
        self?.typingLabel.isHidden = !snapshot.isTyping
    },
    onFailure: { [weak self] error in
        self?.presentError(error)
    }
)

subscribePresence 失败不会部分更新本地集合。 unsubscribePresencelistPresenceSubscriptions 也提供同样的 onSuccess/onFailure 重载;登出或销毁 Client 才会恢复默认受众模式。

6. 附件和安全作用域

通过 NSOpenPanel 取得用户选择的 URL;启用 Sandbox 时只在读取/提交期间访问 安全作用域:

swift
guard url.startAccessingSecurityScopedResource() else { return }
defer { url.stopAccessingSecurityScopedResource() }

client.sendFile(
    conversationID: conversationID,
    fileURL: url,
    displayName: url.lastPathComponent,
    onSuccess: { _ in print("file task accepted") },
    onFailure: { print($0.stableCode, $0.message) }
)

上传任务由 Core 持久化。Window 关闭不取消附件任务;需要业务取消时调用 cancelMediaTask

7. 请求取消、登出和进程退出

swift
let request = client.searchMessages(
    keyword: keyword,
    limit: 50,
    onSuccess: { [weak self] in self?.results = $0.messages },
    onFailure: { error in
        if error.stableCode != "request_cancelled" {
            print(error.message)
        }
    }
)

request.cancel()

普通 XHIMRequest.cancel() 只取消本次等待;已经进入 Outbox 的消息使用 cancelMessage,媒体使用 cancelMediaTask。账号退出调用 logout;应用终止 或账号容器销毁时调用 shutdown。关闭最后一个 Window 不应自动销毁 Client。

8. 回调错误

XHIMCallbackError 的稳定字段:

字段用途
stableCode业务分支,不匹配 message 文案
retryable是否适合用户重试
retryAfterMilliseconds服务端建议的最短等待
userAction登录、升级、释放空间或联系支持
operationID / traceID脱敏诊断与服务端追踪

所有业务 API 的模型、约束和事件载荷继续按模块查阅 SDK API Reference。macOS 的 App Sandbox、窗口管理、睡眠唤醒 和发布验收见 macOS QuickStart

XHIM 客户端 SDK 与服务端文档