主题
晞晗IM(XHIM)平台 Facade 维护指南
适用版本:0.1 Commercial Beta
文档职责:供 XHIM SDK 发行人员维护 C ABI、平台 Facade、线程、内存和发布 边界。普通 App 开发者请直接阅读客户端 SDK 接入总览。
客户端开发者不需要安装 Docker、初始化数据库、配置服务端密钥或执行服务端 脚本。开始接入前,只向服务端负责人领取 Server URL、测试 User ID 和测试 Conversation ID。
0. 第一次接入:不要从 C++ 或 C ABI 开始
如果你的目标是在一个空白 App 中加入晞晗IM,请直接选择你的客户端平台:
| 你正在开发 | 从零接入文档 | UI 包 | 当前可验证程度 |
|---|---|---|---|
| iOS | iOS 空白工程快速接入 / CocoaPods | XHIMSwiftUI | Development XCFramework 已完成真机 + Server 联调 |
| macOS | macOS 空白工程快速接入 | XHIMSwiftUI | Facade/UI 与运行时配置已完成;正式 slice 待发行机生成 |
| Android | Android 空白工程快速接入 | xhim-ui-compose | Facade、媒体上传、系统 Picker 已完成;正式 AAR 待发行机生成 |
| Windows | Windows 空白工程快速接入 | XHIM.UI.Wpf | Facade、媒体上传、WPF Picker 已完成;签名 NuGet 待 Windows 发行机生成 |
| HarmonyOS | HarmonyOS 空白工程快速接入 | ArkUI 组件 | Facade、媒体消息、系统 Picker 已完成;正式 HAR 待 DevEco 发行机生成 |
五个客户端终端已提供同一语义的平台原生一键入口:
text
新建空白工程
→ 添加平台包
→ 填写 Server IP/域名和 User ID
→ 平台 connect API 自动发现部署、创建存储、启动和登录
→ 把 Facade 数据映射给可选 UI Kit
→ Alice/Bob 两端互发
→ 按上线清单移除开发配置不要把 X-XHIM-Admin-Key、JWT 签名私钥或数据库密钥放进客户端。 Development Server 可以显式开启仅凭已创建 User ID 的 Easy Login;Production 会拒绝该开关。正式 App 只在账号容器提供一次业务凭证闭包,SDK 自动初次获取和 过期续期,页面与普通业务代码不处理 Token。UI Kit 也是可选层;不使用 XHIM 默认页面时,Headless SDK 仍可独立完成登录、收发、同步、分页和已读。
各平台 QuickStart 均从空白工程开始,并使用 XHIMClient.connect(iOS/macOS/Android/HarmonyOS)或 XHIMClient.ConnectAsync(Windows)完成发现、账号隔离存储、登录和自动续凭。 iOS 可通过 CocoaPods/SwiftPM,Android 通过 Maven/AAR,Windows 通过 NuGet, HarmonyOS 通过 OHPM/HAR 接入。普通 App 开发者到对应 QuickStart 即可;只有 XHIM 产品构建人员才继续阅读本页后面的 Adapter、C ABI 和发布边界。
0.1 文档结构基线
快速文档的组织方式参考了主流 IM 厂商当前官方教程中已经被开发者验证的共同 路径,而不是复制其 API:
- Sendbird iOS UIKit Getting Started: 从新建 Xcode Project、加 Package、初始化到展示会话;
- Stream Chat iOS SDK: 明确区分 Headless Client 和可选 UIKit/SwiftUI UI 层;
- 腾讯云 IM iOS SwiftUI 接入: 按鉴权、登录、会话列表、聊天、联系人和页面跳转拆步骤。
XHIM 在此基础上增加了私有化 Server、隐藏凭证生命周期的一键登录、可靠 Outbox、服务端序号、 数据库加密、五端签名制品和上线安全检查。任何快速示例都不能为了“几行跑通” 把 Admin Secret 放进 App。
1. 客户端团队可以依赖什么
正式商业交付目标包含:
- 对应平台的二进制 SDK 包,不要求 App 编译 C++ 源码;
- 平台原生 Facade、异步 API、事件流和稳定错误类型;
- 可选 UI Kit、系统相机/相册/视频/文件选择器和媒体消息接口;
- 账号隔离存储、可靠 Outbox、断网恢复、分页同步和已读能力;
- 由服务端负责人交付后可直接填写的 Server URL;
- 不同平台分别提供的空白工程 QuickStart 和上线检查。
当前仓库是 Commercial Beta:已有受控 Apple Development 包;macOS 正式 slice、AAR/Maven、NuGet 和 HAR 的源码/Bridge/组包门禁已验证,但最终签名 二进制仍须由相应发行机生成并通过 clean-consumer 与真机矩阵。不能把源码构建 通过写成客户已经拿到正式制品。
客户端项目不实现 Backend、不直接操作 SQLite,也不持有服务端管理凭证。SDK 内核构建、服务端实现、部署验证和发行门禁不属于客户端接入步骤。
2. 按平台选择指南
| 平台 | 正式目标产物 | 原生入口 | 当前指南 |
|---|---|---|---|
| iOS | XCFramework + Swift Package / CocoaPods | 回调式 API、Swift async/await、AsyncStream | iOS 接入指南 |
| macOS | XCFramework + Swift Package | 回调式 API、Swift async/await、AsyncStream | macOS 接入指南 |
| Android | AAR + Maven 元数据 | Kotlin coroutine、Flow | Android 接入指南 |
| Windows | x64/arm64 DLL + NuGet | C# Task、IAsyncEnumerable、SafeHandle | Windows 接入指南 |
| HarmonyOS / OpenHarmony | arm64-v8a .so + HAR/OHPM | ArkTS Promise、异步迭代/订阅 | HarmonyOS 接入指南 |
四份平台指南都按同一顺序说明:
- 当前状态与客户可依赖的边界;
- 商用包必须包含的文件;
- 从源码验证内核的方式;
- 原生 Facade 应如何封装 C ABI;
- 生命周期、线程、Callback 和内存规则;
- 账号存储、后台、附件媒体与可选 RTC 平台要求;
- UI Kit 分层和二次开发边界;
- 发布前验收清单。
3. 所有平台共同遵守的稳定边界
普通平台 Wrapper 只调用:
text
XHIM::XHIM
└── <xhim/xhim_v1.h>
└── xhim_v1_* C ABIXHIM::Engine、XHIM::Storage、XHIM::Sync、XHIM::Transport、 XHIM::Media 和 XHIM::RTC 是产品 Adapter 与内核联合开发接口。它们包含 C++ 类型、STL、 虚函数表和类布局,在 0.x 阶段不承诺 C++ ABI 兼容,不能暴露给 Swift、Kotlin、 C# 或 ArkTS 业务代码。
平台 Facade 必须把 C ABI 转换为本平台习惯的类型:
| C ABI | 平台 Facade |
|---|---|
xhim_v1_client_t * | 单一所有权 Client 对象 |
xhim_v1_subscription_t * | 可取消订阅/Token |
立即 int32_t 返回值 | 同步参数或准入错误 |
| Completion Callback | async/await、Task 或 Promise |
| Event Callback | AsyncStream、Flow、事件流或订阅 |
xhim_v1_bytes_view_t | Callback 内立即复制的 Data/ByteArray/byte[]/ArrayBuffer |
xhim_v1_error_t | 平台稳定错误类型,完整保留下表中的机器可判定字段 |
错误字段的职责固定如下,宿主不得解析 message 文本来决定业务分支:
| 字段 | 用途 |
|---|---|
code | ABI 级粗粒度状态,兼容既有调用方 |
domain + stable_code | 跨语言、跨版本的业务判断键 |
native_code | 服务端、系统或传输层原始错误码 |
retryable + retry_after_ms | 是否可重试以及最早重试时间 |
user_action | RETRY/UPDATE_CREDENTIAL/CHECK_NETWORK/CONTACT_SUPPORT 等稳定建议 |
operation_id + trace_id | 单次 SDK 操作和服务端链路定位 |
message | 面向开发者的诊断文本,不作为稳定合同 |
新增字段位于 xhim_v1_error_t 的兼容尾部;Bridge 必须先检查 struct_size 再读取尾部字段。旧 Wrapper 仍可按原结构前缀工作,新 Wrapper 必须复制全部字段并映射为平台原生 Error/Exception。
4. 公共生命周期
每个平台都必须维持同一条生命周期:
text
create → start → login → Ready → use
│ ↓
│ logout → login
│ ↓
└→ CredentialRequired
↓ updateCredential(new token)
Ready
任意可运行状态 → shutdown → destroy/disposecreate同步复制app_id和storage_path,并打开/迁移数据库;start启动内核,但不等于登录;login(account_hint, access_token)的 hint 只用于路由,账号最终以服务端认证 返回的 canonicalaccount_id/self_user_id为准;- 认证过期进入
CREDENTIAL_REQUIRED后调用update_credential(access_token); Core 继续使用当前 canonical account,宿主不得重新传入或替换账号 ID; - 只有状态到达
READY后才能发送和读取当前公开的消息/会话 API; logout允许同一 Client 再次登录;shutdown是不可逆终止;- 最终销毁必须与其他 Client API 外部串行化;
- 一个 Client 同时只绑定一个账号,多账号必须使用不同 Client 和不同数据库路径。
- 版本化运行策略在 create 时复制,统一控制请求超时、Sync Page 和有限重连; 账号生命周期内不可变,四套原生 Facade(覆盖五端)均先做范围校验;
- 客户部署可在
create时设置 Bootstrap URL、Endpoint Key ID 和 Ed25519 公钥;三者必须同时出现并由 Facade 复制。它们属于部署配置,不是每次请求可变 参数。API/WSS/上传/下载地址只能来自验签且未过期的 EndpointBundle; - TLS Trust 和生产能力开关不接受业务代码动态关闭,Product Adapter 必须 fail closed。
生产配置必须保持 flags == 0。XHIM_V1_CLIENT_FLAG_LOCAL_PREVIEW 只用于仓库 CLI 和自动化测试;正式制品应设置 -DXHIM_ENABLE_LOCAL_PREVIEW=OFF。
5. Callback、线程和内存
- 同一 Client 的 Event 和 Completion 在 XHIM 私有串行 Callback 线程执行, 不保证是 UI/Main 线程;
- Wrapper 必须在 Callback 内复制所有 byte view,再切换到 UI/Main 线程;
- Callback 可以提交新的异步请求,但不能同步等待另一个 XHIM Callback;
- Wrapper 负责让传入 C 的 callback context 在取消或最终 Callback 完成前存活;
subscription_cancel对同一 handle 只能调用一次,且不能并发调用;client_destroy开始后不得再调用任何 Client API;- 平台对象析构、GC/finalizer 或 ArkTS 回收钩子只能作为泄漏兜底,业务必须提供 明确的
close/dispose/shutdown。
6. 消息、分页和媒体
send_text是text/plain@1的便捷入口;- 其他消息使用不可变
content_type + content_version + payload + fallback_text; - iOS/macOS/Android/Windows/HarmonyOS 均提供
XHIMMessagePluginRegistry(使用 各自语言命名风格)和 UI Renderer Registry。发送自定义消息前先注册并校验, 接收后由插件生成会话/通知摘要;未知类型、高版本或插件异常必须使用fallback_text,不得丢弃原始 Payload 或阻塞 Cursor; client_message_id在一个 storage profile 内全局唯一;重试同一逻辑消息必须 复用同一 ID 和相同 Payload;retry_message(client_message_id)只重新入队当前账号下的永久失败消息,并 原样复用已持久化信封;对已经在 Pending/Retrying 的同一请求幂等成功;cancel_message(client_message_id)只取消尚未被 Transport 获取的本地 Pending/Retrying/Failed 工作;对已经 Cancelled 的消息幂等成功,对 Sending 或 ServerAccepted 明确返回冲突/忙碌,不能声称撤回了已发送消息;- Retry/Cancel 在 Runtime actor 内执行,并受当前账号 Epoch fence 保护; 只有状态实际改变时才发布
MESSAGE_RETRY_QUEUED/MESSAGE_CANCELLED事件; - 分页 Cursor 是账号/查询范围内的不透明二进制值,可能包含 NUL,平台层只能 原样复制和回传;
- Callback 返回的消息和会话数组都是借用内存,必须在 Callback 返回前深拷贝;
- 媒体 Payload 只保存稳定
MediaRef,不能放原始文件、本地 URI、Token 或 临时签名 URL; - iOS、macOS、Android、Windows 和 HarmonyOS 的默认发送路径均创建 Core-owned durable media task,由内核持久化进度、恢复、校验并在 Ready 后写入稳定
MediaRef;旧XHIMMediaUploaderSPI 只保留兼容迁移和特殊客户扩展; - SwiftUI、Compose、WPF 和 ArkUI 均提供系统相机/相册/视频/文件入口。Picker 只返回宿主可读的本地 URI/URL,不在 UI 层上传;ViewModel 将其交给
sendImage、sendVideo、sendAudio或sendFile创建持久媒体任务; - 实时通话不属于纯 IM 首发范围;以后通过独立 Call/RTC Provider 可选包接入, 不走普通消息 Outbox,也不修改消息内核。
xhim_v1_client_mark_conversation_read() 已提供服务端权威的跨设备已读。 调用方应在聊天页已经展示服务端确认消息后,取其中最大的正 server_seq, 连同会话 ID 提交;本地 Pending/Sending 消息没有服务端序号,不能作为已读 目标。Core 会先确认目标序号已经存在于当前账号的本地时间线,再请求服务端, 只有服务端回包成功后才原子更新 SQLite 的 read_seq/unread_count,不做乐观 清零。
服务端按 (app_id, conversation_id, user_id) 保存单调 read sequence,并把 变更作为不可跳过的账号 Sync 事件投递给当前用户的其他设备。同值或更低值是 成功 no-op,不重复发布变更事件;高于服务端会话最新序号、非会话成员或跨账号 请求必须拒绝。Completion 返回服务端确认的会话 ID、已读序号、剩余未读数和 更新时间;CONVERSATION_READ_CHANGED 只携带会话 ID,UI 收到后应重新读取 该会话摘要,而不是自行推算未读数。iOS、macOS、Android、Windows 和 HarmonyOS 的 对应原生方法与线程规则见各平台接入文档。
附件媒体和未来可选 RTC 的完整边界见 商用媒体消息与实时音视频架构。
服务端社交协议位于 protocol/proto/xhim_social_v1.proto,包括好友申请、 接受/拒绝、社交快照、建群、带 expected_revision 的成员增删和成员分页。 所有成功变更与账号事件流在同一服务端事务提交,WebSocket 仍只发送 Sync Hint; 客户端必须通过 /v1/sync 拉取权威事件,不能把 Hint 当作业务数据。
当前 C++ xhim_v1 已暴露好友申请、好友、群、群成员、黑名单和入群申请的 稳定分页查询,并通过 Schema v12 写入账号隔离的本地 SQLite 投影;iOS、macOS、 Android、Windows 和 HarmonyOS 在线 Client 与 OfflineReader 已提供对应的 强类型分页。后续增量 API 仍必须直接复制这些 C ABI 页面,不能绕过 Core 自建长期关系缓存。
7. 存储路径和安全
平台层必须把数据库放在应用私有、可写且不会被系统临时清理的目录。不要使用 Bundle/安装目录、共享 Downloads、外置公共目录或 Cache 目录作为主数据库。
建议路径语义:
text
<app-private>/xhim/<app-id>/<account-profile>/xhim.sqlite3account-profile 应使用不可逆或服务端分配的不透明目录名,不要直接使用手机号、 邮箱或 Token。Token、数据库密钥、媒体密钥和日志脱敏策略由平台安全存储层负责。 同一数据库不得由多个进程、两个 Client 或不兼容 SDK 版本并发打开。
8. UI Kit 和二次开发边界
商业包应拆成两个可独立依赖的产品:
text
XHIM Headless Facade
├── 生命周期、账号、会话、消息、附件媒体 API
├── 自定义消息插件、摘要和版本兼容
└── 平台原生模型和事件流
XHIM UI Kit(可选)
├── 会话列表
├── 聊天页和消息 Cell/Renderer
├── 联系人、群组和搜索
└── 图片/文件组件
XHIM Call Kit(未来可选)
└── 厂商 RTC Provider、通话 UI 与系统通话桥UI Kit 只能依赖 Headless Facade,不能直接调用 C ABI、打开 SQLite 或持有 C++ 对象。二次开发通过主题 Token、自定义消息 Renderer、动作拦截、页面路由和资源 Provider 扩展;删除 UI Kit 后,Headless SDK 必须仍然完整可用。
9. 产品构建团队入口
需要实现真实认证、HTTP/WSS、Codec、对象存储或未来 RTC Provider 时,阅读:
不要在 iOS、macOS、Android、Windows、HarmonyOS 五个原生 OS 的 Wrapper 中 各写一套登录、重连、Sync、Outbox 或媒体状态机。Swift 实现可以在 iOS/macOS 间复用,但两个客户入口和验收矩阵必须独立。平台层只处理语言绑定、平台生命周期、 系统能力和 UI;跨平台业务状态必须回到唯一的 C++ Core。
10. 客户项目验收
每个对外发布的平台包至少通过:
- 空白项目只依赖最终发布包,不引用 XHIM 源码即可编译运行;
- 加载后校验
xhim_v1_abi_version() == XHIM_V1_ABI_VERSION; - 错误 Token 不进入 Ready,未配置 Backend 明确 fail closed;
- 登录、发送、本地查询、分页、logout、换号和 shutdown 生命周期完整;
- Callback 不在 UI 线程时,Facade 正确切线程且无借用内存越界;
- 进程重启、升级迁移、断网、弱网、后台恢复和磁盘不足有确定结果;
- 包含版本、Commit SHA、支持矩阵、符号文件、Hash、许可证、NOTICE 和 SBOM;
- UI Kit 可选卸载,自定义 Renderer 和主题不会修改内核数据。
客户端验收只使用最终平台制品和服务端负责人交付的测试环境,不执行内核或 服务端构建脚本。服务端与 SDK 发行团队各自按照对应文档完成自己的验收,不能 代替五个平台最终制品、应用商店环境和真机验收。