主题
iOS 回调式 API
适用版本:0.1 Commercial Beta
适用模块:XHIM
最低版本:iOS 15、Swift 5.9
本页是 iOS 开发者的首选 API 入口。它采用与主流 IM SDK 相同的 onSuccess / onFailure 形式,不要求接入者先理解 Swift async throws。 所有回调都在 MainActor 执行,可以直接更新 UIKit / SwiftUI 状态。
原有 Swift Concurrency API 完整保留,适合 Repository、批处理和高级并发控制。 两套入口调用的是同一个 XHIM Core,不会形成两份状态或两套数据库。
1. 回调类型
swift
typealias XHIMSuccessCallback<Value> = (Value) -> Void
typealias XHIMFailureCallback = (XHIMCallbackError) -> Void
typealias XHIMEventCallback = (XHIMEvent) -> Void| 类型 | 用途 |
|---|---|
XHIMRequest | 一次异步请求的句柄;调用 cancel() 取消等待中的请求 |
XHIMEventListenerToken | 账号事件监听句柄;释放或调用 cancel() 即退订 |
XHIMCallbackError | 稳定错误对象,包含 code、stableCode、retryable 和 traceID |
XHIMRequest.cancel() 只取消当前 API 请求。已经进入 Outbox 的消息用 cancelMessage,持久媒体任务用 cancelMediaTask。
2. 连接并登录
方法原型
swift
XHIMClient.connect(
server:userID:appID:authentication:storageRootURL:
onConnecting:onConnectSuccess:onConnectFailure:
) -> XHIMRequest参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
server | String | 是 | XHIM Server 基地址,例如 https://im.example.com |
userID | String | 是 | 当前业务用户 ID |
appID | String? | 否 | 单租户可省略,由服务端公开配置返回 |
authentication | XHIMAuthentication | 否 | Development 默认免 Token;Production 使用 business provider |
storageRootURL | URL? | 否 | 自定义账号数据库根目录,通常省略 |
回调
| 回调 | 参数 | 触发时机 |
|---|---|---|
onConnecting | 无 | SDK 开始发现配置、启动 Core 并建立连接 |
onConnectSuccess | XHIMClient | 登录、连接和首次同步完成 |
onConnectFailure | XHIMCallbackError | 任一步骤失败 |
Development 示例
swift
private var client: XHIMClient?
private var connectRequest: XHIMRequest?
connectRequest = XHIMClient.connect(
server: "https://im-test.example.com",
userID: "alice",
onConnecting: {
print("XHIM 正在连接")
},
onConnectSuccess: { [weak self] client in
self?.client = client
print("XHIM 已连接")
},
onConnectFailure: { error in
print("连接失败:", error.code, error.message)
}
)Development Server 显式启用免密测试登录时,客户端只填写 server 和 userID。App 不需要手工申请、保存或续期测试 Token。
Production 示例
swift
connectRequest = XHIMClient.connect(
server: "https://im.example.com",
userID: account.userID,
authentication: .business(
AccountService.shared.xhimCredential
),
onConnecting: {
connectionState = .connecting
},
onConnectSuccess: { [weak self] client in
self?.client = client
self?.connectionState = .connected
},
onConnectFailure: { [weak self] error in
self?.showConnectionError(error)
}
)AccountService.xhimCredential 属于 App 自己的账号层。页面不接触 Token; XHIM 需要续期时会自动再次调用它。
3. 添加事件监听
方法原型
swift
client.addEventListener(_:) -> XHIMEventListenerToken示例
swift
private var eventToken: XHIMEventListenerToken?
eventToken = client.addEventListener { [weak self] event in
switch event {
case .stateChanged(let state):
self?.updateConnectionState(state)
case .messageUpserted(let change),
.messageStateChanged(let change):
self?.reloadMessages(conversationID: change.conversationID)
case .conversationChanged:
self?.reloadConversations()
case .conversationReadChanged:
self?.reloadUnreadCount()
case .presenceChanged(let update):
self?.updatePresence(update)
case .typingChanged(let update):
self?.updateTyping(update)
default:
break
}
}必须先保存监听 token,再查询首屏。退出账号时:
swift
eventToken?.cancel()
eventToken = nil事件是“本地投影已变化”的通知,不是完整消息副本。收到消息或会话事件后,调用 查询 API 刷新对应页面。
4. 获取或创建单聊
方法原型
swift
client.directConversation(
with:onSuccess:onFailure:
) -> XHIMRequest示例
swift
client.directConversation(
with: "bob",
onSuccess: { conversation in
self.openChat(conversationID: conversation.conversationID)
},
onFailure: { error in
self.showError(error.message)
}
)不要在客户端自行拼接单聊会话 ID。
5. 发送文字消息
方法原型
swift
client.sendText(
conversationID:clientMessageID:text:
onSuccess:onFailure:
) -> XHIMRequest参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
conversationID | String | 是 | 服务端返回的会话 ID |
clientMessageID | String? | 否 | 幂等 ID;省略时由 SDK 生成 |
text | String | 是 | 文字内容 |
示例
swift
let messageID = UUID().uuidString.lowercased()
client.sendText(
conversationID: conversationID,
clientMessageID: messageID,
text: "你好,晞晗IM",
onSuccess: { receipt in
print("消息已进入发送队列:", receipt.payload)
},
onFailure: { error in
if error.retryable {
self.showRetryButton(clientMessageID: messageID)
} else {
self.showError(error.message)
}
}
)成功表示可靠 Outbox 已接受消息,不等于对端已读。最终发送状态通过消息查询和 messageStateChanged 事件刷新。
6. 发送自定义消息
方法原型
swift
client.sendMessage(
conversationID:clientMessageID:message:
onSuccess:onFailure:
) -> XHIMRequest示例
swift
let payload = Data(
#"{"orderID":"20260728001","amount":199}"#.utf8
)
let message = XHIMOutgoingMessage(
contentType: "com.example.order.card",
contentVersion: 1,
payload: payload,
fallbackText: "[订单] 20260728001"
)
client.sendMessage(
conversationID: conversationID,
message: message,
onSuccess: { _ in
print("自定义消息已入队")
},
onFailure: { error in
print(error.stableCode, error.message)
}
)自定义类型必须使用自有命名空间、正整数版本和安全 fallback。配套解析与 UI Renderer 见二次开发扩展点。
7. 查询会话列表
方法原型
swift
client.conversations(
cursor:limit:onSuccess:onFailure:
) -> XHIMRequest示例
swift
client.conversations(
limit: 50,
onSuccess: { page in
self.items = page.conversations
self.nextCursor = page.nextCursor
},
onFailure: { error in
self.showError(error.message)
}
)下一页把 page.nextCursor 原样传回 cursor。收到 conversationChanged 后重新查询第一页。
8. 查询消息列表
方法原型
swift
client.messages(
conversationID:cursor:limit:onSuccess:onFailure:
) -> XHIMRequest示例
swift
client.messages(
conversationID: conversationID,
limit: 50,
onSuccess: { page in
self.messages = page.messages
self.nextCursor = page.nextCursor
},
onFailure: { error in
self.showError(error.message)
}
)查询更早的服务端历史使用:
swift
client.getMessageHistory(
conversationID: conversationID,
continuation: historyContinuation,
limit: 50,
onSuccess: { page in
self.prepend(page.messages)
self.historyContinuation = page.continuation
},
onFailure: { error in
self.showError(error.message)
}
)9. 已读和未读
标记会话已读
swift
client.markConversationRead(
conversationID: conversationID,
throughServerSequence: latestServerSequence,
onSuccess: { receipt in
self.unreadCount = receipt.unreadCount
},
onFailure: { error in
self.showError(error.message)
}
)查询总未读
swift
client.totalUnreadCount(
onSuccess: { count in
UIApplication.shared.applicationIconBadgeNumber = Int(count)
},
onFailure: { error in
print(error.message)
}
)全部标记已读
swift
client.markAllConversationsRead(
mutationID: UUID().uuidString,
onSuccess: { result in
self.reloadConversations()
print("已更新会话数:", result.changedConversationCount)
},
onFailure: { error in
self.showError(error.message)
}
)10. 用户、好友与群组查询
这些查询具有相同的 onSuccess / onFailure 结构:
swift
client.currentUserProfile(
onSuccess: { profile in self.profile = profile },
onFailure: { error in self.showError(error.message) }
)
client.userProfiles(
userIDs: ["alice", "bob"],
onSuccess: { batch in self.consume(batch) },
onFailure: { error in self.showError(error.message) }
)
client.friendships(
limit: 50,
onSuccess: { page in self.friends = page.items },
onFailure: { error in self.showError(error.message) }
)
client.groups(
limit: 50,
onSuccess: { page in self.groups = page.items },
onFailure: { error in self.showError(error.message) }
)
client.groupMembers(
conversationID: groupID,
limit: 50,
onSuccess: { page in self.members = page.items },
onFailure: { error in self.showError(error.message) }
)同类回调式查询还包括 friendRequests、blocks 和 groupJoinRequests。
11. 媒体任务
图片、视频、语音和文件由 SDK 建立持久媒体任务。创建任务成功不代表上传完成, 最终状态通过 mediaTaskUpdated 监听并用 mediaTask 查询。
swift
client.sendImage(
conversationID: conversationID,
fileURL: attachment.localURL,
mimeType: attachment.mimeType,
width: 1080,
height: 1920,
onSuccess: { task in
self.observeMediaTask(task.taskID)
},
onFailure: { error in
self.showError(error.message)
}
)
client.mediaTask(
taskID: taskID,
onSuccess: { task in
self.updateProgress(task)
},
onFailure: { error in
self.showError(error.message)
}
)同样提供 sendVideo、sendAudio 和 sendFile 回调接口;需要完全自定义 持久任务参数时使用 acceptMediaUpload。
取消持久媒体任务:
swift
client.cancelMediaTask(
taskID: taskID,
onSuccess: { task in self.updateProgress(task) },
onFailure: { error in self.showError(error.message) }
)12. 失败回调与错误处理
swift
func handle(_ error: XHIMCallbackError) {
switch error.userAction {
case .retry:
showRetryButton()
case .updateCredential:
accountService.refreshLogin()
case .checkNetwork:
showNetworkNotice()
case .contactSupport:
showSupport(traceID: error.traceID)
case .none:
showError(error.message)
}
}| 字段 | 用途 |
|---|---|
code | 平台稳定整数错误码 |
domain | 错误子系统 |
stableCode | 业务分支和统计的稳定字符串 |
retryable | 是否允许使用同一幂等 ID 重试 |
retryAfterMilliseconds | 建议的最短等待时间 |
userAction | 推荐的用户或账号层动作 |
operationID / traceID | 客服与服务端排障 |
message | 日志和用户提示,不用于业务判断 |
13. 退出登录
swift
client.logout(
onSuccess: { [weak self] in
self?.eventToken?.cancel()
self?.eventToken = nil
self?.client = nil
},
onFailure: { error in
print("退出失败:", error.message)
}
)账号容器销毁时还应调用 shutdown() 完成不可逆资源释放。需要完全使用 Swift Concurrency 的团队,可继续查阅100 个 API 并发示例。