Skip to content

可信业务通知消息合同

1. 消息信封

Core 识别精确类型 application/vnd.xhim.business-notification+json 和 version 1。payload 必须与 服务端 Go encoding/json 产生的 canonical 字节完全一致:

json
{
  "schema_version": 1,
  "visibility": "server_visible",
  "encrypted": false,
  "title": "系统维护",
  "body": "今晚 23:00 开始",
  "data": {"ticket_id": "maintenance-1"}
}

上面为易读展示;线上字节不含缩进和多余空白,顶层字段顺序固定。 data 可省略,但出现时必须是 canonical JSON object。边界为:

  • payload 最多 64 KiB;
  • title 最多 512 UTF-8 字节,不得包含 NUL,且必须已等于 Go strings.TrimSpace 后的值;
  • body 最多 48 KiB,不得包含 NUL,且不能只有 Unicode 空白;
  • data canonical 字节最多 48 KiB,最深 64 层,对象键按 Go UTF-8 字符串顺序排列,重复键拒绝;
  • 字符串遵循 Go JSON 转义:<>&、U+2028 和 U+2029 必须转义; 数字保留 json.Number 的有效词法,包括 -0、指数和超大整数。

Go 生成器为 scripts/dev/generate_business_notification_golden.go, 跨语言固定向量为 compatibility/protocol-golden/business_notification_v1.tsv

2. 失败安全与本地历史

typed parser 是一个可选展示投影,不是 Sync 接纳条件。未来 version、 未知字段、重复键、非 canonical 转义、超限或恶意 payload 仍按 content_type + content_version + payload + fallback_text 原样写入 SQLite/历史/同步。它们只有 typed projection unavailable,不能导致消息丢失。

Reference Product Adapter 和 Apple Product Adapter 共用同一个 generic ServerCodec::decode_sync;该 codec 对通知无专用分支,并原样保留 content type、version、payload 和 fallback。

3. UserProfile 类型投影

服务端账号类型为 human | notification_servicexhim_social_v1.proto.UserProfile.user_type = 17 是 additive 权威字段: UNSPECIFIED=0 表示旧服务端、旧缓存或当前 SDK 不识别的值, HUMAN=1NOTIFICATION_SERVICE=2。Core 保留未来非负 raw value; SQLite v34 迁移对 v33 行填 UNKNOWN=0,等后续服务端权威 profile 覆盖,绝不把旧行猜成 human。

C ABI 在不改变 xhim_v1_user_profile_snapshot_t 224 字节大小和数组 stride 的前提下,将尾部 reserved_profile_u32 复用为 int32_t user_type。 不往 application_extension_json 塞私有字段,也不根据 user ID 前缀推断。

XHIM 客户端 SDK 与服务端文档