主题
二次开发扩展点
1. 自定义消息
业务消息使用稳定四元组:
text
contentType + contentVersion + payload + fallbackText推荐命名:
text
com.customer.product.order-card
com.customer.product.live-invite
com.customer.product.workflow-approval不要使用 custom1、页面类名或会随重构变化的字符串。版本只属于一个 contentType;兼容增加字段时升版本,改变业务含义时创建新类型。
swift
let outgoing = XHIMOutgoingMessage(
contentType: "com.example.shop.order-card",
contentVersion: 1,
payload: encodedOrder,
fallbackText: "[订单] ¥199.00"
)
_ = try await client.sendMessage(
conversationID: conversationID,
message: outgoing
)1.1 用户资料公开业务扩展
UserProfile.application_extension_json 与自定义消息不同:它是与用户 资料一起同步的小型、应用拥有、对陌生人也公开的 JSON object,不是私密 存储、凭证保险箱或通用文档库。推荐 key 采用业务命名空间,例如:
json
{
"crm.label": "gold",
"workflow.enabled": true
}规则:非空值必须是 UTF-8 JSON object,服务端规范化后最大 16 KiB、 嵌套最大 64 层;省略更新字段表示不改,空 bytes 表示清除。严禁写入 手机、邮箱、实名、密码、Token、会话/认证状态、加密密钥或任何其他 个人敏感和认证数据。需要当前账号私有数据时,使用专用私有业务存储, 不要依赖 private_profile_visible 隐藏该字段。
2. Message Plugin
XHIMMessagePlugin / Windows IXHIMMessagePlugin 定义:
| 成员 | 用途 |
|---|---|
contentType | 插件唯一负责的稳定类型 |
supportedVersions | 当前 SDK 可以解释的版本范围 |
validate | 发送前和展示前验证 payload |
presentation | 生成会话预览、通知预览和 renderer key |
XHIMMessagePluginRegistry 公开:
| api-id | iOS / macOS / Android / HarmonyOS | Windows | 说明 |
|---|---|---|---|
extension.plugin_register | register | Register | 注册;重复 contentType 失败 |
extension.plugin_unregister | unregister | Unregister | 删除注册并返回是否存在 |
extension.plugin_validate | validate | Validate | 校验 outgoing message |
extension.plugin_present | presentation | Present | 把收到的消息转为展示描述 |
Registry 放在 App 的 IM 组合根中只创建一次。不要让每个 Cell 注册插件,也不要 在 Plugin 中发网络请求。
未知类型或未知版本的规则固定:
- 保留完整
XHIMMessage; - 展示
fallbackText; - 不执行未知 payload;
- 升级后可重新渲染已有历史消息。
3. 内置标准消息工厂
XHIMStandardMessageFactory:
| api-id / 工厂 | 内容 |
|---|---|
extension.standard_sticker — sticker / Sticker | 表情包 ID、资源 URL 和描述 |
extension.standard_location — location / Location | 纬度、经度、标题和地址 |
extension.standard_contact_card — contactCard / ContactCard | 用户 ID、展示名、头像 |
extension.standard_red_packet — redPacket | 红包业务单据引用、祝福语、状态和业务路由 |
extension.standard_transfer — transfer | 转账业务单据引用、最小货币单位金额、币种、状态和业务路由 |
extension.standard_enterprise_card — enterpriseCard | 审批、任务、公告、日程等企业业务卡片 |
extension.standard_markdown — markdown / Markdown | 受限 Markdown 源文本和纯文本降级内容 |
extension.standard_quote — quote / Quote | 被引用消息身份、发送者和摘要 |
extension.standard_mention — mention / Mention | 文本、用户 ID 列表、是否 @所有人 |
extension.standard_merged_forward — mergedForward / MergedForward | 标题和不可变 XHIMForwardItem 列表 |
XHIMMentionContent.decode(Windows Decode)可以从收到的 Message 解码 @ 信息,并用 mentions(userID) 判断是否命中当前用户。 Apple 端使用 XHIMQuoteContent.decode 和 XHIMMergedForwardContent.decode 读取收到的引用与合并转发内容;不要在 App 中重复实现 Protobuf 解析。
这些工厂只负责消息 envelope,不授予位置、通讯录或相册权限;系统权限由宿主 App 明确请求。
Markdown 使用稳定的 text/markdown@1 信封。SDK 只校验、编码和传输源文本, 不会执行 HTML,也不会把 Markdown 直接转换成富文本。宿主 Renderer 必须关闭 原始 HTML、脚本 URL 和不受信任的远程资源;不能安全渲染时始终显示 plainTextFallback。工厂收到空 fallback 时会把 Markdown 源文本作为字面纯文本 降级,保证旧端仍能阅读且不会执行标记。
红包、转账和企业卡片都是“业务单据引用消息”,不是资金或审批执行引擎。IM 服务只保证消息可靠投递、版本兼容、会话预览和历史保存;余额、支付密码、实名、 风控、审批权限和最终业务状态必须由购买方的业务服务校验。客户端点击卡片时, 先校验允许的 actionURL scheme/host,再向已登录业务模块请求最新状态,不能 相信历史消息中的 state 就直接付款、领款或通过审批。
Apple 示例:
swift
let transfer = try XHIMStandardMessageFactory.transfer(
transferID: order.id,
amountMinor: order.amountFen,
currency: "CNY",
note: "项目报销",
state: .pending,
actionURL: "myapp://wallet/transfers/\(order.id)"
)
_ = try await client.sendMessage(
conversationID: conversationID,
message: transfer
)
let approval = try XHIMStandardMessageFactory.enterpriseCard(
businessID: approvalID,
category: "审批",
title: "采购申请待处理",
summary: "申请人:王晓晨",
state: "pending",
actionURL: "myapp://oa/approvals/\(approvalID)",
participantUserIDs: approverUserIDs
)C++ Core 和 C ABI 已经把消息 envelope 当作不透明、可版本化载荷可靠保存,因此 其他端可以立即使用相同 contentType@1 和 xhim_content_v1.proto 编码收发, 无需改动 Core。各端便利工厂和 Renderer 应以协议文件为唯一字段来源。
4. Renderer
UI Kit 的 Renderer Registry 以 rendererKey 或 contentType 选择消息 Cell / Composable / WPF DataTemplate / ArkUI Component。
Renderer 输入只依赖:
XHIMMessage- Plugin 给出的
XHIMMessagePresentation - 主题与宿主路由闭包
Renderer 不直接调用 C ABI、不读取 SQLite、不持有 Token。点击订单卡片、名片 或位置时,通过宿主注入的路由闭包回到购买方业务模块。
各端入口:
| 平台 | UI/Renderer 入口 |
|---|---|
| iOS | XHIMSwiftUI 的 message renderer registry 和 SwiftUI View |
| macOS | XHIMSwiftUI Renderer;AppKit 可使用 NSHostingView |
| Android | xhim-ui-compose 的 message renderer registry / Composable |
| Windows | XHIM.UI.Wpf.XHIMMessageRendererRegistry |
| HarmonyOS | XHIMMessageRendererRegistry / XHIMMessageItemRenderer |
5. UI Kit 可替换边界
text
App Navigation / Theme / Business Screens
└── XHIM UI Kit(可选)
├── Conversation List
├── Chat Timeline + Composer
├── Attachment Picker
└── Message Renderer Registry
└── Headless XHIMClient购买方可以:
- 替换导航、主题、字体、颜色和本地化;
- 只使用会话列表或聊天页的一部分;
- 完全不用 UI Kit,自己用 Facade 构建 MVVM/VIP 页面;
- 注册业务消息 Renderer;
- 替换相机、相册、文件和录音入口;
- 注入用户头像、业务页面路由和权限提示。
购买方不需要、也不应修改:
- XHIM Core 二进制;
xhim_v1C ABI;- SDK 数据库 schema;
- Outbox、同步和媒体 durable task 状态机;
- Endpoint 验签和凭证轮换逻辑。
6. Attachment Picker
UI 包提供的 Picker 是薄适配层:
| 能力 | iOS | macOS | Android | Windows | HarmonyOS |
|---|---|---|---|---|---|
| 拍照/视频 | AVFoundation / UIImagePicker | AVFoundation | Activity Result / Camera | 宿主相机服务 | 系统 Picker |
| 相册 | PhotosPicker | PhotosPicker / NSOpenPanel | Photo Picker | FileOpenPicker | PhotoViewPicker |
| 文件 | UIDocumentPicker | NSOpenPanel + 安全作用域 | Storage Access Framework | FileOpenPicker | DocumentViewPicker |
| 录音 | AVAudioRecorder | AVAudioRecorder | MediaRecorder | 宿主录音服务 | AVRecorder |
Picker 返回本地受权资源后,统一交给 durable media API,而不是把路径塞入消息。
7. Repository 与 ViewModel
推荐每个登录账号创建一个组合根:
text
XHIMService
├── XHIMClient
├── MessagePluginRegistry
├── ConversationRepository
├── MessageRepository
├── SocialRepository
└── MediaRepositoryRepository 的读模型来自 SDK Query API;事件只触发重新查询。ViewModel 只消费 Repository 状态并调用业务动作。这样二次开发可以替换 UI,而不会把连接、同步、 事件和 Token 逻辑散落在页面里。
8. 扩展兼容清单
发布新的自定义消息前至少验证:
- 当前版本正常收发和渲染;
- 旧版本只显示 fallback,不崩溃;
- iOS/macOS/Android/Windows/HarmonyOS payload 字节一致;
- Push 通知预览不泄露敏感字段;
- 合并转发和引用只保存必要快照;
- 内容审核能根据 contentType 路由;
- Renderer 失败时回退到普通未知消息气泡;
- 消息复制、搜索、清空、撤回和离线 Reader 不破坏未知 payload。
9. 语音转文字与翻译 Provider
XHIM::Enrichment 提供供应商中立的 C++17 MessageEnrichmentProvider SPI。购买方可以适配阿里云、腾讯云或 已审核的本地模型;XHIM 不内置云凭证,也不会用 Fake Provider 伪装生产能力。
| api-id | 能力 | 说明 |
|---|---|---|
extension.enricher_create | 创建 Provider 隔离的 Enricher | 创建时复制配置与 vtable;旧 Core 明确 unsupported |
extension.enricher_transcribe | 提交语音转文字 | 音频字节或安全本地句柄二选一;有界进度与终态 |
extension.enricher_translate | 提交消息翻译 | 明文边界和远端处理同意都必须显式填写 |
extension.enricher_cancel | 幂等取消一个 Request ID | 迟到 Provider 回调由 epoch fence 丢弃 |
extension.enricher_close | 停止 Provider 并释放 Enricher | 支持从 progress/completion 回调中安全重入 |
Enricher 不属于 XHIMClient 的消息可靠传输状态机:它不能读取数据库、Token 或 E2EE 密钥,也不会自动把结果写回消息。宿主只把用户明确选择的输入交给 Provider,并自行决定如何展示结果。Provider 回调可能同步发生,因此各平台 Facade 都先复制借用内存,再切换到语言自己的 Task/Coroutine/Promise 机制。
完整输入上限、请求/观察者 epoch fence、超时、取消、错误分类、 Provider 适配和 E2EE 明文边界见 Message Enricher 接入与安全边界。