# SuperSDK 离线包远程清单规范 v1(super_meta.json) > **状态:定稿 v1**(对应 Feature `SDK-F260716075511-Offline-Pkg-Spec-V1` AC-1;下游消费方 S6/CA-F024 按本规范产出清单) ## 概述 `super_meta.json` 是 SuperSDK 离线包**远程更新**能力的唯一契约:站点方(S6/CA-F024 等发布管道)在站点根路径发布这份清单,SDK 双端(Android / iOS)在打开对应 host 的页面时后台探测该清单,据此判断是否有新版离线包可下载安装。 - **谁产出**:站点发布管道(如 S6/CA-F024),或本地用 `packages/jssdk/super_package.sh` 打包时同步生成(参考实现,见下文)。 - **谁消费**:SuperSDK Android / iOS 客户端(`OfflineRemoteUpdater`,内部实现,不对外暴露)。 - **格式**:站点根路径下的静态 JSON 文件。 ## 数据结构 ### 字段表 | 字段 | 类型 | 必填 | 校验规则 | 默认值 | 备注 | |------|------|------|----------|--------|------| | `__ver` | int | 是 | 必须 `== 1`,否则整份清单被拒绝 | - | 清单**格式**版本号,与包内 `__super_meta.json` 的 `__ver` 是两套独立计数,互不关联 | | `host` | string | 是 | 必须与被探测站点的 origin host **完全一致**(大小写不敏感);不一致则整份清单被拒绝 | - | 仅用于清单自证归属;SDK 落盘目录名**只取实际探测到的 origin host**,永远不信任此字段做路径拼接 | | `version` | string | 是 | `x.y.z` 格式(与 `super_package.sh` 的版本号校验规则一致);必须与 zip 包内 `__super_meta.json.app_version` 相等,安装时不等按校验失败处理 | - | 离线包版本号 | | `md5` | string | 是 | 32 位十六进制字符串,须与下载后 zip 文件的实测 MD5 完全一致 | - | zip 文件 MD5 | | `size` | long | 是 | 必须 `> 0`;自动探测模式下若 `> 50MB`(`50 * 1024 * 1024` 字节)则跳过下载(仅显式调用可下);下载完成后若实际字节数与本字段不符,按校验失败处理并清理临时文件 | - | zip 文件字节数 | | `pkg_path` | string | 是 | 站点根**相对路径**:禁止包含 `://`(scheme)、禁止以 `/` 或 `//` 开头、禁止包含 `..` 路径段、禁止包含 `\`;实际下载地址由 SDK 用 `https://{探测到的 origin host}/{pkg_path}` 拼出(URL 编码后),**强制同源** | - | zip 包下载地址(相对形式),任何清单都不能指向站点自身以外的地址 | ### 最小 JSON 示例 ```json { "__ver": 1, "host": "mainpage.demo.supersdk.site", "version": "1.3.2", "md5": "9a0364b9e99bb480dd25e1f0284c8555", "size": 1048576, "pkg_path": "__super/mainpage.demo.supersdk.site@1.3.2@9a0364b9e99bb480dd25e1f0284c8555.zip" } ``` ### Serve 位置 清单必须发布在站点根路径: ``` https://{host}/super_meta.json ``` - 不存在(404)是**合法且常见**的正常状态(表示该站点未接入远程更新),SDK 静默处理,不视为错误。 - 路径固定为站点根,SDK 不支持自定义清单路径。 ## 与包内 `__super_meta.json` 的关系 离线包体系里存在**两份 meta**,职责不同、不能混淆: | | `super_meta.json`(本规范) | 包内 `__super_meta.json` | |---|---|---| | 层次 | **传输层**:告诉 SDK「最新版 zip 在哪、多大、指纹是什么」 | **内容层**:描述 zip 内部文件清单,用于安装时逐文件校验 | | 位置 | 站点根路径,SDK 下载 zip **之前**读取 | zip 包内部,SDK 解压**之后**读取 | | 结构 | 六字段(本文档) | `{__ver, app_version, build_time, file_map}`(由 `super_package.sh` 自动生成) | | 产出方 | 站点发布管道(S6/CA-F024) | `super_package.sh` 打包时自动写入目标目录 | 两者通过 **`version == app_version`** 交叉锁定:清单声明的 `version` 必须与下载到的 zip 包内 `__super_meta.json.app_version` 一致,否则视为校验失败,不会替换本地已安装的旧包。 ## zip 命名与工具链约束 - **命名规则**:`{host}@{version}@{md5}.zip`,与 `super_package.sh` 现行产物格式一致,本规范对既有打包产物**零改动、完全兼容**。 - **打包工具链约束(重要)**:zip 必须由标准 deflate 压缩工具产出(如 `zip -r`,与 `super_package.sh` 内部实现一致),**禁止使用流式写出(streaming / data descriptor)方式产 zip**。 - 原因:iOS 端 `ZipArchive` 是自研的 zip 解析器,按 local file header 顺序扫描解压,**不读取 central directory**;若 zip 条目使用 data descriptor(`compressedSize`/`crc32` 置 0,实际值写在数据块之后),iOS 解析器无法正确解压,会导致离线包在 iOS 上安装失败。 - 凡是经 `zip` 命令行工具(非 `-fd`/流式模式)或等价标准工具产出的 zip 均满足本约束;用自定义流式打包脚本产 zip 前,务必先用真机联测验证 iOS 侧可正常解压。 ## SDK 消费行为摘要 以下是 SDK 双端消费本清单时的行为约定,供站点方理解客户端表现(详细实现见 SDK 内部技术方案,不属于本规范的契约内容): | 行为项 | 约定 | |--------|------| | 探测时机 | SDK 打开任意 http(s) 页面时,在页面加载 hook(Android `onPageStarted` / iOS `load(url:)` + `didStartProvisionalNavigation`)后台异步探测该 host 的 `super_meta.json`,不阻塞页面渲染 | | 探测频控 | 每个 host 最小间隔 **30 分钟**(进程内计时,不持久化);间隔内的探测直接跳过(含 404/网络失败也占用该间隔,避免无清单站点被反复请求) | | 自动下载上限 | 自动探测模式下,清单 `size` 超过 **50MB** 时跳过下载,仅记录日志;显式调用宿主 API(见下)可绕过该上限 | | 同源绑定 | 清单 `host` 字段必须与实际探测到的页面 origin host 完全一致;`pkg_path` 解析后的下载地址强制拼接到该 origin host,任何清单都无法指向其他域名的资源 | | 生效时机 | 新版本下载安装成功后,**下次加载**该 host 页面时生效;不会热刷新当前已打开的页面 | | 失败处理 | 清单 404 / 网络失败 / 格式非法 / 校验不通过:自动探测模式下**静默**(仅记日志,不影响页面),旧包保持可用;显式调用宿主 API 触发的更新失败会通过回调通知宿主 | > 显式触发接口:Android `IOfflineController.preloadPackage(host, listener)` / iOS 对应 API,详见 `release_doc/supersdk/dev/Android/README.md`、`release_doc/supersdk/dev/iOS/README.md` 的「离线包远程更新」章节。 ## 变更记录 | 日期 | 变更 | |------|------| | 2026-07-21 | v1 定稿(对齐 Feature SDK-F260716075511 AC-1 / S6 消费锚点) |