Skip to content

布局协议 ​

布局是单个显示器的可保存排布。其依赖是本地已安装且协议兼容的组件,并非“订阅过”,也不以授权为前置条件。

每个显示器的当前状态直接使用布局格式持久化,配置不独立保存。布局库保存/覆盖复制当前屏布局,应用或恢复覆盖该屏当前布局;存档属于安装组件,不进入布局。实例身份由安装内部身份与显示器身份稳定派生,不携带配置。

当前schemaVersion=1,每个条目必须提供zOrder;muted可省略,默认为false,组件依赖仅记录 UUID,不记录组件来源。当前只接受下述规范 v1,不接受带来源字段的基线前变体,不自动转换历史格式;后续范围及迁移遵循格式版本规则(宿主文档:../development.md#格式版本兼容与迁移)。allowMultipleInstances=false且其他屏已有启用实例时,预览提示冲突并禁止应用或恢复;事务提交再次校验,不自动停用其他屏。

文件格式 ​

本地导出为 UTF-8 JSON 文件;工坊布局内容目录包含 layout.json 与可选 preview.png,条目标签区分 layout/widget。preview 可采用宿主排布示意图;若用户主动选择截图,上传前必须展示图像以避免意外分享组件内容。

json
{
  "schemaVersion": 1,
  "kind": "layout",
  "layoutId": "cb0302a9-292e-43b1-a267-246ffb536022",
  "version": "1.0.0",
  "name": "双栏工作屏",
  "sourceResolution": {"width": 1920, "height": 1080},
  "sourceWorkArea": {"widthDip": 1920, "heightDip": 1040},
  "items": [
    {
      "component": {
        "widgetId": "f1846617-c096-4c41-b6d1-4622f9b12ab1",
        "hostApiMajor": 1
      },
      "componentName": "系统信息",
      "enabled": true,
      "visible": true,
      "muted": false,
      "layer": "bottom",
      "zOrder": 0,
      "bounds": {"x": 32, "y": 32, "width": 320, "height": 200},
      "configuration": {"title": "工作站", "refreshSeconds": 5}
    }
  ]
}

组件引用形式为 {widgetId:"...",hostApiMajor:1},不保存 source、appId 或 publishedFileId。依赖仅按 UUID 匹配已安装组件,与本地、开发或工坊来源无关;同 UUID 多个安装时拒绝歧义,不任意选择。宿主API版本必须为1,不支持的引用禁止应用。工坊发布保留相同引用,不要求组件来自工坊,也不提供引用重绑定。

schemaVersion、kind、layoutId、version、name、sourceResolution、sourceWorkArea、items 必填;sourceResolution 为保存时完整显示区域的物理像素正整数宽高(不是工作区或 DIP),每项 componentName 为非空名称快照。组件不可重复身份仅由 component.widgetId 确定,名称不参与匹配。其余规则:version 格式与组件包一致。items 可为空,表示清空目标屏当前布局;同一组件 UUID 最多一次。enabled/visible 必须为布尔值,layer 必须为 top/bottom。sourceWorkArea 宽高必须为正;bounds 为有限 DIP 数值,宽高为正。未知字段、重复 JSON 键、重复组件引用和不支持的协议均拒绝导入。已保存的当前屏布局允许读取结构有效但运行代际不兼容的安装引用,以保留启用意图;应用/恢复仍检查引用代际与激活版本一致且为宿主所支持。

zOrder 为 0 到 2147483647 的整数,同一 layer 内不得重复,越大越靠前;不同层可重复,top 始终位于 bottom 之上。隐藏条目同样保留顺序。预览与实际应用使用同一排列。

对外布局文件不保存目标显示器的本机 ID、真实设备路径、权限、绑定、秘密、浏览数据或安装包内容。当前布局和本地布局库保存完整配置及有效绑定引用,以configurationTypes记录字段类型;类型变化时采用当前默认值,避免将资源引用转换为普通文本。对外导出只含通过 分享规则 的普通字段。组件版本不强制精确锁定;要求 hostApiMajor 匹配,运行当前激活的本地版本。预览按当前配置模式验证配置,不合法项标明将回落的默认值。

应用布局从默认值构造条目,再用布局中的合法配置覆盖,不合并当前配置;缺失字段采用默认值或 null。未列出的条目从当前布局移除,实例资源停止;独立存档、KV与浏览数据不随布局覆盖删除。同机本地布局的绑定引用只在仍属于当前安装且有效时恢复;外部导入仍拒绝绑定。

布局 JSON 最大 1 MiB、items 最多 100 条;这些是输入处理上限,不是产品保证可以同时流畅运行 100 个组件。实例唯一约束、字段校验和资源预算仍独立执行。

应用与恢复 ​

  1. 选择目标显示器,确认已连接且物理像素宽高与 sourceResolution 一致,否则禁止应用或覆盖。解析布局并校验引用;逐项检查是否存在已完整安装、兼容、未待清理的本地激活版本。列出缺失项及运行不兼容的组件和原因,任一依赖不可用即禁用应用按钮,不自动订阅或下载。
  2. 在数据层计算适配与配置变化,显示新增、替换、停用及默认值回落。预览不运行新组件、不修改状态,也不检查用户是否授予 Capability。
  3. 用户确认后取得目标屏布局操作锁,重新检查显示器、依赖、版本和配置模式,保存原状态快照,再准备候选状态与窗口。新窗口准备期间不启动作者脚本;失败保留原状态。
  4. 原子提交候选状态;目标屏中未列出的条目移除,其既有配置不在当前布局中保留,列出的组件按布局的 enabled/visible/layer/zOrder 排布。不复制到其他屏,不改变安装级授权。
  5. 完成窗口切换后开始新实例运行,保留应用前快照。资源创建或切换失败回滚原布局;提交后作者脚本失败按运行故障处理,可手动恢复,不把任意脚本业务逻辑成功作为事务条件。

每屏保留最近一次应用前快照,不形成无限历史。恢复也需预检依赖与当前资源;缺依赖时拒绝并列出。恢复只作用于目标屏、排布和有效配置,不恢复被撤销的授权、不重建已清理的绑定或组件。快照更新遵循原子提交,不覆盖唯一可恢复状态直到新应用成功。

应用期间目标屏断开或组件被卸载时取消未提交操作;若已提交,按最后完整状态记录并等待显示器恢复,不能迁移到主屏。删除内容、更新激活与布局应用由应用服务协调顺序,避免校验后身份失效。

分辨率与 DPI 适配 ​

坐标相对显示器工作区左上角,单位 DIP,工作区不包含任务栏保留区域。保存和导出同时记录工作区 DIP 宽高与完整显示区域的物理像素分辨率。布局跨屏通用,但应用和覆盖必须匹配物理分辨率;DPI 和任务栏差异继续适配。物理像素到 DIP 由目标显示器 DPI 换算,不能用主屏缩放统一换算。

位置按 x' = x × targetWidth/sourceWidth、y' = y × targetHeight/sourceHeight 映射。尺寸使用目标实例最后的作者请求值,新实例使用包默认尺寸,布局 bounds.width/height 仅记录保存时作者尺寸供预览,不能覆盖作者尺寸;恢复同样不回滚作者当前尺寸。宿主不因小屏缩小组件,仅将位置夹紧到工作区;尺寸超过工作区时左上位置约束到工作区边界,允许部分内容超出。

允许组件重叠,不自动重新排列;预览明确实际结果,只可调整位置,尺寸由作者决定。任务栏、DPI 或分辨率变化时按同样规则约束位置,不改变尺寸与组件身份。处理规则应有确定性测试,而非依赖窗口创建顺序。

本地保存与分享 ​

本地布局库直接复制当前屏全部布局条目,包括停用条目、普通配置、静音和有效绑定引用;库记录属于本机内部状态,不能原样作为传播文件。导出及工坊发布必须重新走字段筛选,生成上例形式的独立文件,不输出绑定。导入文件严格校验,不能因为来自自己的导出就跳过。

组件取消订阅后,现有布局保留排布和缺失引用;其中该组件的个人配置清空,恢复快照的配置及绑定引用也清空,不能借恢复找回已清理数据。已主动导出到用户选定目录或已发布到工坊的外部文件不是应用内部备份,不在组件清理中搜索或改写。

格式拒绝与覆盖 ​

名称快照在导入、导出及组件卸载后保留。旧协议文件不读取、导出或转换;已有本地旧记录不自动删除,使用当前屏重新保存排布。覆盖在原布局 ID 下原子提交当前屏的新排布,保留布局名,失败不改变记录或当前屏状态。

当前宿主协议 · SDK 0.1.1 · MIT