协议 V1

API 文档

设计一个 Glance Widgets 能够渲染的接口,你需要知道的都在这里:小组件会发送什么请求、你的接口应当返回什么格式的响应,以及渲染器遵循的规则。本页每个实时示例,都由与 App 相同的规则渲染。

概览#

Glance Widgets 小组件由对你自己接口的一次 HTTPS GET 请求驱动。接口返回一个 JSON 对象,即一帧画面,用来描述要绘制的内容。App 会校验并规范化这一帧,再由 WidgetKit 渲染到主屏幕上。

一帧画面包含两个相互叠加的表达通道:

  • 根点阵(pixels):最多 4,096 个点位的矩形点阵,以整个小组件画布为布局区域。可以为每个点单独设置样式,也可以把大部分交给 default 与 batch。
  • 图层:带定位尺寸的内容元素,包括文字、曲线、图片、图标、线条、形状与局部点阵。
容器(Liquid Glass、玻璃、纯色、渐变、环境光或图片)在 App 中配置,而不是由你的 API 决定。你的响应只负责绘制在容器之上的内容。唯一的例外是图片容器:它可以读取 data 中的图片,让服务端渲染整张画面,见服务端整图渲染。

快速开始#

最小的有效响应就是一个点阵。像素点样式数组中的元素为 null 继承 default,显式对象则覆盖它。

示例
{
  "protocol": 1,
  "default": { "color": "#8EC8FB", "opacity": 0.12, "cornerRadius": 0.5 },
  "pixels": [
    [null, null, null, null, null],
    [
      null,
      { "color": "#7EDDB5", "opacity": 1 },
      null,
      { "color": "#7EDDB5", "opacity": 1 },
      null
    ],
    [null, null, null, null, null],
    [
      { "color": "#DFFF70", "opacity": 1 },
      null,
      null,
      null,
      { "color": "#DFFF70", "opacity": 1 }
    ],
    [
      null,
      { "color": "#DFFF70", "opacity": 1 },
      { "color": "#DFFF70", "opacity": 1 },
      { "color": "#DFFF70", "opacity": 1 },
      null
    ]
  ]
}
小尺寸小组件上的 5 × 5 点阵
  • 把接口部署到任何支持 HTTPS 的地方。
  • 在 App 中创建一个小组件,并将 URL 粘贴到 API 字段。
  • 以真实主屏幕尺寸预览,然后将小组件添加到主屏幕。

小组件的内容结构#

卡片的材质与内容

小组件的表达由卡片本身的风格材质和卡片中的内容构成。风格材质只能在 App 或未来某些其他平台的自定义小组件编辑器中设置,无法通过 API 指定、动态更新。API 负责的是卡片中的内容及其样式。

卡片中的图层有两个来源。第一种是编辑器图层:在编辑器的可视化操作台中手动添加、摆放和设置,保存在小组件配置里。它可以完全静态;也可以填写一个数据路径,让 API 在每次响应中更新它的位置、内容与样式,此时编辑器中的设置就是首次取得数据前的初始状态,也是响应缺少某个字段时的兜底。

第二种是远程图层:编辑器中不做任何配置,由 API 在每次响应中声明。它可以是小组件配置里根本没有的内容,内容的原始定义完全来自 API。两种图层可以同时使用,具体写法见“响应体”和“图层”。

基础图层与点阵

在 Glance Widgets 里,可以通过添加文本、直线、曲线、图片、图标、形状等类型的图层,实现对基础内容的表达;它们的摆放可以重叠,通过专门的 zIndex 字段控制层级。

在此基础上,为了便捷地拓展表现力,同时保持描述、解析的简单易用,又提供了点阵类型。用户可以通过自己的服务端程序,实现各种想要的表达。像素屏这一实质,使得丰富的表达成为可能,而描述起来又仅仅是一个二维数组,非常简单。前面几种基本类型的内容,也同样可以通过像素点阵表达,实现像素风,完全取决于个人偏好与需要;实际精细度受点阵单元数预算限制。

点阵的表达同样分为两种。点阵图层(type: "matrix")和前面几种图层一样,在容器画布的指定位置、尺寸开辟一片区域,绘制局部点阵,其内容 content 就是一份点阵。另一种是根点阵(顶层 pixels):它不属于图层系统,而是在整个小组件内容画布上布局。根点阵的样式系统、渲染规则和 API 形式,与点阵图层没有本质区别。额外设立这一机制,主要是为了在只需要统一样式的纯像素风点阵表达一个简单主题、无需把多个局部点阵与其他图层组合时,让实现更简单直接。根点阵按 layout 等比适配并居中;是否视觉上铺满卡片,取决于点阵与画布的宽高比、间距及边缘设置。

点阵本身是由数个点单元构成的网格系统。用户除了可以定义每个点的样式,还可以让某个点不显示。确切地说,网格系统随着局部或整个根点阵的开辟始终存在,逻辑上的点位不会消失,但你可以决定某些点位什么都不显示、空出来,就像老式黑底红字的像素屏一样。以此空出特定区域,实现特定样式,或叠加其他内容图层,共同构成表达。{"empty": true} 的具体规则会在“像素与优先级”中展开。

最终的三层结构

  • 最底层:卡片风格材质,作为背景板和容器,由编辑器配置。
  • 中间层:根点阵,在整个内容画布上布局,可以局部留白,也可以完全留空。
  • 最上层:各种内容图层,包括编辑器图层和 API 声明的远程图层,统一按 zIndex 合成。局部点阵也属于这一层。

请求#

小组件发送 HTTPS GET 请求。你自己的查询参数会被保留,App 会追加保留的 gw_* 参数,用来描述它要绘制的空间。非 HTTPS 的 URL 会被拒绝。

gw_protocol
示例1
说明客户端使用的协议版本。
gw_platform
示例ios
说明客户端平台。
gw_family
示例small · medium · large
说明小组件尺寸类型。
gw_canvas_width_pt
示例158.00
说明可用内容画布宽度,以 iOS 逻辑像素(pt)计,保留两位小数。
gw_canvas_height_pt
示例158.00
说明可用内容画布高度,以 iOS 逻辑像素(pt)计,保留两位小数。
gw_aspect_ratio
示例1.0000
说明宽 ÷ 高(保留四位小数)。
gw_context
示例app_preview
说明渲染上下文。app_home:App 首页;app_preview:编辑预览;widget:主屏幕小组件。
gw_state_<key>
示例—
说明为未来的交互状态扩展预留,当前请求流程尚未使用。所有 gw_ 开头的参数名均由客户端保留使用,请勿用作自定义查询参数。

pt 是 iOS 的逻辑尺寸单位,在 App 的 Flutter 端对应逻辑像素,不是屏幕物理像素,也不是点阵点位数。例如在 3 倍屏幕缩放倍率下,158 pt 对应 474 个物理像素的长度。这两个参数都已扣除卡片的内容内边距:宽度 = 小组件外框宽度 − 2 × contentInset,高度同理,最小值为 1 pt。

画布尺寸因设备而异。在宽度为 390–393 pt 的 iPhone 上,各尺寸大致为 158 × 158(小)、338 × 158(中)和 338 × 354(大)。

请求示例
GET https://api.example.com/widget?team=core&gw_protocol=1&gw_platform=ios&gw_family=medium&gw_canvas_width_pt=338.00&gw_canvas_height_pt=158.00&gw_aspect_ratio=2.1392&gw_context=app_preview

超时较短:App 中发送约 8 秒,接收约 12 秒。任何 2xx 状态码都视为成功。请返回 UTF-8 编码的 JSON,并尽量带上 Content-Type: application/json。

响应体#

响应体必须是一个 UTF-8 JSON 对象,最大 512 KB。protocol 可省略,建议显式返回 1;其他非空版本值不受支持。它描述本次请求的一帧内容,按三组理解:根点阵、数据根 data、远程图层声明 layers。未知的顶层字段会被忽略。

根点阵:pixels、default、layout、batch

pixels 确定网格的m*n大小并描述点的样式,layout 决定这些点如何组合成整体。复杂画面即便用服务端程序拼接二维数组,逐点绘制仍然繁琐;因此用 batch 表达一批相同样式的点,用 default 处理没有单独声明样式的点。

pixels
类型 / 取值(Pixel | null)[][]
用途与规则根点阵内容,必填。每个元素对应网格中一个点的样式,按 pixels[row][column] 访问;原点在左上角。矩形、至少 1 × 1,最多 4,096 个点位。
default
类型 / 取值Pixel
用途与规则没有单独声明样式时采用的缺省值;也为显式像素对象和每个 batch 的省略字段提供回退值。
layout
类型 / 取值MatrixLayout
用途与规则描述整个根点阵如何组合、布局:点之间的间距、单元宽高比、所占空间的边缘如何处理。它不描述单个点的颜色或形状。
batch
类型 / 取值{ pixel, coordinates }[]
用途与规则为一批具有相同样式的点声明 pixel,用从零开始的 [row, column] 坐标选中点位。适合由服务端程序生成规律图案,减少逐点重复声明。

覆盖顺序是 default → 按数组顺序应用 batch → pixels 中的显式对象。null 保留 default / batch 的结果;显式对象中省略的字段回退到 default,不会逐字段叠加 batch。这里“省略点的样式”是用 null 保留点位,不能删掉数组元素或缩短某一行。具体规则和示例见“像素与优先级”。

数据根:data

data 是一个可选对象,省略时为空对象,用来存放图层要读取的内容。字段名称与嵌套结构由你决定,可以按业务组织,例如把同一块面板的图层都放在 data.orders 下。图片材质的数据路径也从这里读取图片(见服务端整图渲染)。

data 本身只是一个可自由编排的对象,其值本身不会自动显示。编辑器内创建的动态内容,或你在 API 中构建返回的远程图层,会通过 dataPath 读取你指定的某个 data 内字段,并按照规则解析、绘制。如果这个字段是用来驱动编辑器图层或远程图层的,它必须是一个对象,并按图层类型遵循一定的协议规则。大体通用的结构是:在 dataPath 指向的这个字段里,包含该图层的位置、内容和样式,详见下面的 layers 和“图层”一章。

远程图层:layers

layers 是可选数组,省略时没有远程图层。数组中的每一项声明一个由 API 新增的图层,有且只有 id、type、dataPath 三个字段:id 以 remote: 开头且在本次响应中唯一,type 是七种图层类型之一,dataPath 指向 data 中描述这个图层的对象。

图层的位置、内容和样式不写在 layers 的条目里,而是写在 dataPath 指向的对象里:frame、zIndex、rotation、transform 决定尺寸和布局,content 是内容,style 是样式。远程图层完全由这个对象构造,所以必须带有 frame。

声明一个远程图层
{
  "protocol": 1,
  "pixels": [[{ "empty": true }]],
  "data": {
    "orders": {
      "badge": {
        "frame": { "right": 0.07, "top": 0.14, "width": 0.24, "height": 0.2 },
        "content": { "text": "LIVE" },
        "style": { "color": "#0B1222", "backgroundColor": "#7EDDB5", "opacity": 1, "cornerRadiusRatio": 1 }
      }
    }
  },
  "layers": [
    { "id": "remote:badge", "type": "text", "dataPath": "data.orders.badge" }
  ]
}

每次响应的 layers 描述当前这一帧的完整远程图层集合,下一次成功响应整体替换,不是增量修改指令。编辑器中添加的图层不在 layers 中声明,它们由编辑器里填写的数据路径绑定,规则见“图层”一章。

即使只使用图层,根点阵 pixels 仍然必填。返回 [[{"empty": true}]] 可使根点阵完全留空,让图层显示在卡片材质之上。

响应体完整类参考#

下面以树状嵌套对象和关联类型列出响应结构。? 表示字段可省略,[] 表示数组,| 表示可选类型;这是类型参考,不是可直接返回的 JSON。layers 中的 type 决定对应的 content / style 类型,不能把其他类型的字段混用。图层字段的具体用途、单位和生效条件见后文。

V1 响应类型参考
type WidgetResponse = {
  protocol?: 1
  pixels: (Pixel | null)[][]
  default?: Pixel
  layout?: MatrixLayout
  batch?: Batch[]
  // Objects that layers point to live anywhere in data; layers only declare remote layers.
  data?: { [key: string]: JsonValue | LayerNode }
  layers?: {
    id: `remote:${string}`
    type: 'text' | 'matrix' | 'curve' | 'image' | 'icon' | 'line' | 'shape'
    dataPath: string // points to the object in data that describes this layer
  }[]
}

// The object a dataPath points to. type selects content and style:
// text → TextContent / TextStyle, matrix → MatrixContent / (none),
// curve → CurveContent / CurveStyle, image → ImageContent / ImageStyle,
// icon → IconContent / IconStyle, line → LineContent / LineStyle,
// shape → (none) / ShapeStyle
type LayerNode = {
  frame?: Frame // required for remote layers
  zIndex?: number
  rotation?: number
  transform?: { translateX?: number; translateY?: number }
  content?: object
  style?: object
}
type Frame = {
  width: number; height: number
  left?: number; right?: number; top?: number; bottom?: number
}

type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue }
type Color = string // #RRGGBB / #AARRGGBB
type GapMode = 'zero' | 'near' | 'default' | 'far' | 'extraFar'
type Pixel = {
  color?: Color; opacity?: number; cornerRadius?: number
  rotation?: number; halo?: number; empty?: boolean
}
type Batch = { pixel: Pixel; coordinates: [row: number, column: number][] }
type MatrixLayout = {
  gapMode?: GapMode; edgeInsetRatio?: number; cellAspectRatio?: number
  columnGapRatio?: number; rowGapRatio?: number
}

type MatrixContent = {
  pixels?: (Pixel | null)[][] // required for remote layers
  default?: Pixel; batch?: Batch[]; layout?: MatrixLayout
}

type TextContent = { text?: string | number }
type TextStyle = ChromeStyle & {
  color?: Color; textOpacity?: number; fontSizeRatio?: number
  fontWeight?: '300' | '400' | '500' | '600' | '700'
  fontFamily?: 'system' | 'systemMonospace' | 'monospace'
  fontFamilyFallback?: string[]; letterSpacing?: number; baselineRatio?: number
  horizontalAlignment?: 'left' | 'center' | 'right'
  verticalAlignment?: 'top' | 'center' | 'bottom'
  autoWrap?: boolean; paddingRatio?: number
}
type ChromeStyle = EffectsStyle & {
  backgroundColor?: Color; opacity?: number
  cornerRadiusRatio?: number
  borderColor?: Color; borderOpacity?: number; borderWidth?: number
  gradientEnabled?: boolean; gradientColors?: Color[]
  gradientStops?: number[]; gradientAngle?: number
}
type EffectsStyle = {
  maskColor?: Color; maskOpacity?: number
  vignetteIntensity?: number
  readabilityGradient?: 'none' | 'top' | 'bottom' | 'left' | 'right' | 'both'
    | 'topLeftDiagonal' | 'topRightDiagonal'
}
type ShapeStyle = ChromeStyle & { color?: Color }
type ImageContent = { url?: string }
type ImageStyle = ChromeStyle & { color?: Color }
type IconContent =
  | {
      icon?: string; iconCodePoint?: number
      iconFont?: 'phosphorBold' | 'devicon' | 'simpleIcons' | 'material'
    }
  | { url?: string }
type IconStyle = {
  color?: Color; textOpacity?: number
  iconGlowEnabled?: boolean; iconGlowColor?: Color
  iconGlowOpacity?: number; iconGlowRadius?: number
}
type LineContent = { direction?: 'horizontal' | 'vertical' }
type LineStyle = {
  color?: Color; opacity?: number; strokeWidth?: number
  pattern?: 'solid' | 'dashed' | 'dotted'; cap?: 'round' | 'butt'
  dashLength?: number; dashGap?: number
  gradientEnabled?: boolean; gradientColors?: Color[]; gradientStops?: number[]
}

type CurveContent = {
  mode?: 'samples' | 'function'
  points?: [x: number, y: number][]
  expression?: string; parameters?: { [name: string]: number }
  domain?: [number, number]; yDomain?: [number, number]
  interpolation?: 'linear' | 'stepAfter' | 'monotone'
  markers?: {
    at: { x?: number; sampleIndex?: number; offsetPt?: [number, number] }
    symbol?: { shape?: 'circle'; radiusPt?: number; fill?: Color }
    label?: string
    labelStyle?: {
      color?: Color; fontSizePt?: number
      position?: 'top' | 'bottom' | 'left' | 'right'
    }
  }[]
}
type CurveStyle = {
  color?: Color; opacity?: number; strokeWidth?: number
  lineCap?: 'round' | 'butt' | 'square'; lineJoin?: 'round' | 'bevel' | 'miter'
  dashLength?: number; dashGap?: number
  fillColor?: Color; fillOpacity?: number; plotPadding?: number
}

像素样式#

以下字段描述单个像素点的样式,写在根点阵的 default、batch[].pixel 或 pixels[row][column] 中,也适用于点阵图层 content 中的 default、batch[].pixel 和 pixels。

color
范围#RRGGBB · #AARRGGBB
说明十六进制颜色。8 位形式是透明度在前(ARGB),而不是 CSS 的 #RRGGBBAA。
opacity
范围0 – 1
说明控制点的可见度,超出范围会被截断;与颜色的 alpha 相乘,0 完全透明,1 不额外降低不透明度。
cornerRadius
范围0 – 0.5
说明圆角半径相对于像素点短边:0 为直角,0.5 为最大圆角;正方形像素点此时为圆形,矩形像素点为胶囊形。
rotation
范围度
说明45 会把方形变成菱形。
halo
范围0 – 1
说明点的发光强度,0 为关闭;用于强调亮点或营造像素屏的发亮质感。
empty
范围boolean
说明true 表示跳过该像素点的绘制。

根点阵如果省略 default,像素点的初始值为 color #0A2D48、opacity 0.28、cornerRadius 0.18。需要鲜明、完全不透明的颜色时,请设置 opacity: 1。

像素与优先级#

每个单元按固定顺序解析,优先级从低到高:

  • default(若未提供,则使用内置初始值)
  • 每个 batch 条目,按数组顺序,后面的样式对象替换前面的;每项省略的属性均从 default 补齐
  • pixels 中显式的非 null 值

null 表示此处不覆盖,而不是透明。{"empty": true} 是显式留白:不绘制任何内容,但该单元仍占据点阵中的位置。显式的像素对象在省略颜色等字段时回退到 default,而不是下层的 batch 样式。empty 是显式留白标记:当 default 为 {"empty": true} 时,null 点位仍为空,但显式的普通像素对象会重新绘制该点。

示例
{
  "protocol": 1,
  "layout": { "gapMode": "near" },
  "default": { "color": "#18313A", "opacity": 0.34, "cornerRadius": 0.18 },
  "pixels": [
    [
      { "color": "#7CFFB2", "cornerRadius": 0.18 },
      null,
      { "color": "#F4BC54", "rotation": 45 }
    ],
    [
      { "empty": true },
      { "color": "#FFFFFF", "opacity": 0.7 },
      null
    ]
  ],
  "batch": [
    {
      "pixel": { "color": "#38A6FF", "cornerRadius": 0.5, "opacity": 1 },
      "coordinates": [
        [0, 1],
        [1, 2]
      ]
    }
  ]
}
default → batch → 显式 pixels

Batch 坐标是从零开始的 [row, column] 整数对,且必须位于点阵之内;超出范围的坐标会让 App 拒绝整个画面。

点阵布局#

以下字段描述整个点阵的布局,写在响应体的 layout 对象中,也适用于点阵图层的 content.layout。

点阵会等比适配到画布内(contain)并居中,保留像素点的宽高比。间距与边缘留白均以像素点的短边为基准;它们不是相对于整个卡片的百分比。edgeInsetRatio、columnGapRatio 和 rowGapRatio 的取值表示单个像素点短边长度的倍数,gapMode 用于选择预设的间距倍数;cellAspectRatio 则表示像素点的宽高比。

gapMode
取值zero · near · default · far · extraFar
默认值default
用途相邻像素点之间的间距预设,依次为单个像素点短边长度的 0、0.08、0.16、0.28、0.42 倍,同时用于水平和垂直方向。
edgeInsetRatio
取值−0.45–0.45
默认值0
用途点阵四周的边缘留白 = 单个像素点短边长度 × 此值。正值增加留白;负值让边缘像素点向绘制区域外延伸,超出部分会被裁剪。
cellAspectRatio
取值0.1–10
默认值1
用途单个像素点的宽度 ÷ 高度。1 为正方形,小于 1 为竖向长条,大于 1 为横向长条;不改变点阵的行数和列数。
columnGapRatio
取值0–10
默认值—
用途相邻两列像素点之间的水平间距 = 单个像素点短边长度 × 此值。设置后覆盖 gapMode 的水平间距,省略时使用 gapMode 预设。
rowGapRatio
取值0–10
默认值—
用途相邻两行像素点之间的垂直间距 = 单个像素点短边长度 × 此值。设置后覆盖 gapMode 的垂直间距,省略时使用 gapMode 预设。
适配公式
aspect = cellAspectRatio
short = min(aspect, 1)
gx = (columnGapRatio ?? gapModeRatio) * short
gy = (rowGapRatio ?? gapModeRatio) * short
inset = edgeInsetRatio * short
spanX = columns * aspect + (columns - 1) * gx + 2 * inset
spanY = rows + (rows - 1) * gy + 2 * inset
cellHeight = min(canvasWidth / spanX, canvasHeight / spanY)
cellWidth = cellHeight * aspect
示例
{
  "protocol": 1,
  "default": { "color": "#FFFFFF", "opacity": 0.1, "cornerRadius": 0.5 },
  "layout": { "gapMode": "near", "cellAspectRatio": 0.32, "edgeInsetRatio": 0.45 },
  "pixels": [
    [
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#7EDDB5", "opacity": 1 },
      { "color": "#FFB86B", "opacity": 1 },
      { "color": "#FFB86B", "opacity": 1 },
      { "color": "#FFB86B", "opacity": 1 },
      null,
      null,
      null,
      null,
      null,
      null,
      null
    ]
  ]
}
单行仪表:cellAspectRatio 0.32

图层#

图层是扁平的,没有嵌套,也没有子级。它们绘制在根点阵之上,远程图层与编辑器图层一起按 zIndex 合成,zIndex 相同时按 id 排序。

图层声明

layers 中的每一项声明一个远程图层:

id
类型string
说明以 remote: 开头,在本次响应中唯一。用于区分图层,并在 zIndex 相同时决定绘制顺序。
type
类型string
说明text · matrix · curve · image · icon · line · shape,决定 dataPath 指向的对象中 content、style 可用的字段。
dataPath
类型string
说明描述这个图层的对象在 data 中的位置,语法见下文“数据路径”。

声明多出或缺少字段、id 前缀错误或重复、type 未知、dataPath 语法错误时,整个响应无效。

描述动态图层

不论是在编辑器内添加、作为自定义小组件配置保存的编辑器图层,还是纯 API 返回的远程图层,它们都通过一个路径指向 data 内的某个字段。前者在编辑器内对应的表单项中填写路径,后者则写在前面提到的 dataPath 字段中。dataPath 指向的对象结构都相同,由布局、内容和样式三部分组成:

frame
类型object
说明位置与尺寸,详见下文。远程图层必填;编辑器图层可选,给出时整体替换编辑器中的位置与尺寸。
zIndex
类型integer
说明叠放顺序,较大值绘制在较小值之上。远程图层默认 0。
rotation
类型度
说明围绕图层中心旋转整个图层。远程图层默认 0;点阵中单个点的旋转使用像素样式的 rotation。
transform
类型object
说明translateX、translateY:在 frame 定位之后再平移,单位是图层自身宽、高的比例。
content
类型object
说明图层内容,字段由 type 决定,见“图层样式与内容”。
style
类型object
说明图层样式,字段由 type 决定。matrix 没有样式字段,因为它的样式中,有关整体点阵呈现的基本属于 layout,有关某个具体像素点绘制的信息则放在了 pixels 的二维数组中,包括默认缺省样式、点批量应用样式,也都放在了 content 中。

该对象只接受上表中的字段,content、style 也只接受对应类型字段表中的字段。字段省略或为 null 都表示“不提供”。

小组件图层的合并规则

  • 优先级为 dataPath 指向的对象 > 编辑器设置 > 渲染器默认值。
  • content、style 中的对象字段逐字段合并到编辑器保存的值上,例如点阵的 content.default、content.layout;字符串、数字、布尔值和数组整体替换。
  • frame 总是整体替换:锚点只有放在一起才有意义,把响应的 right 合并到编辑器保存的 left 上,只会被 left 压过。因此给出 frame 时必须包含 width 和 height。
  • 字段省略或为 null 时沿用编辑器的值;0、false 和空数组都是有效的覆盖值。
  • 每次响应都从保存的配置重新计算。下一次响应不再返回某个字段时,该字段恢复为编辑器设置;请求失败时继续显示最近一次成功的响应。

点阵、文本、曲线、线条和形状图层在编辑器中有「当前预览」开关,它只决定编辑页显示什么:选择默认样式时,编辑页只显示编辑器中的值,方便调整兜底外观。App 首页、主屏幕和 StandBy 始终应用响应中的值。

编辑器中保存的图层(示意)
[
  {
    "id": "local:title",
    "type": "text",
    "frame": { "left": 0.07, "top": 0.12, "width": 0.6, "height": 0.16 },
    "zIndex": 10,
    "content": { "text": "Orders today" },
    "style": {
      "color": "#A9C4E8",
      "fontSizeRatio": 0.1,
      "fontWeight": "500",
      "horizontalAlignment": "left"
    }
  },
  {
    "id": "local:total",
    "type": "text",
    "frame": { "left": 0.07, "top": 0.32, "width": 0.6, "height": 0.4 },
    "zIndex": 11,
    "dataPath": "data.orders.total",
    "content": { "text": "—" },
    "style": {
      "color": "#FFFFFF",
      "fontSizeRatio": 0.26,
      "fontWeight": "700",
      "horizontalAlignment": "left"
    }
  }
]
API 响应
{
  "protocol": 1,
  "pixels": [
    [
      { "empty": true }
    ]
  ],
  "data": {
    "orders": {
      "total": {
        "content": { "text": 128 },
        "style": { "color": "#7EDDB5" }
      },
      "badge": {
        "frame": {
          "right": 0.07,
          "top": 0.14,
          "width": 0.24,
          "height": 0.2
        },
        "zIndex": 12,
        "content": { "text": "LIVE" },
        "style": {
          "color": "#0B1222",
          "fontSizeRatio": 0.08,
          "fontWeight": "700",
          "horizontalAlignment": "center",
          "verticalAlignment": "center",
          "backgroundColor": "#7EDDB5",
          "opacity": 1,
          "cornerRadiusRatio": 1
        }
      }
    }
  },
  "layers": [
    {
      "id": "remote:badge",
      "type": "text",
      "dataPath": "data.orders.badge"
    }
  ]
}
两个编辑器图层,其中一个填了数据路径;外加一个远程图层

上例中,local:title 没有数据路径,始终显示编辑器中的文字;local:total 绑定 data.orders.total,该对象只给出文字和颜色,字号、字重和位置仍来自编辑器;remote:badge 由 layers 声明,位置、内容和样式全部来自 data.orders.badge。

位置与尺寸

frame 定义图层在内容画布中的位置和尺寸。所有值都用比例表示:水平方向以画布宽度为基准,垂直方向以画布高度为基准。例如 width: 0.5 表示图层宽度为画布宽度的一半,top: 0.1 表示图层上边缘距离画布顶部为画布高度的 10%。

  • 宽高必填:width、height 设置图层宽高。给出 frame 时,两者都必须提供。
  • 靠一侧定位:用 left / right、top / bottom 设置与画布对应边缘的距离。例如 right: 0.1 表示图层右边缘距离画布右边缘为画布宽度的 10%。
  • 同时指定两侧:left 和 right 同时设置时,图层填满两侧留白之间的宽度,width 不参与计算。例如两者都为 0.1,图层宽度就是画布宽度的 80%。top 和 bottom 同理。
  • 未指定位置:左右都不设置时,图层从画布最左侧开始;上下都不设置时,从最顶部开始。width、height 的取值限制在 0.02–1.5。
frame 示例
{
  "left": 0.1,
  "top": 0.1,
  "width": 0.4,
  "height": 0.2
}

若内容画布为 200 × 100 pt,上例会得到:距左侧 20 pt、距顶部 10 pt,图层宽 80 pt、高 20 pt。再加上 "transform": {"translateX": 0.5},图层会以自身宽度为单位右移一半,即再右移 40 pt。

width / height
类型 / 范围0.02–1.5
用途必填。宽度 / 高度占画布对应轴的比例;同轴两侧锚点同时存在时,该轴尺寸由两锚点决定。
left / right
类型 / 范围number
用途到左边 / 右边的距离占画布宽度的比例。两侧皆省略时从左侧 0 开始;仅 right 存在时右侧对齐。
top / bottom
类型 / 范围number
用途到顶边 / 底边的距离占画布高度的比例。两侧皆省略时从顶部 0 开始;仅 bottom 存在时底部对齐。
transform.translateX / translateY
类型 / 范围number
用途定位后的平移量,分别以图层自身的宽、高为单位;正值向右、向下。

数据路径

dataPath 从 data 开始,逐级访问字段与数字索引,例如 data.orders.total、data.cards[0]。不支持表达式、通配符或字符串键。它必须指向一个对象。

可接受的语法
^data(?:\.[A-Za-z_][A-Za-z0-9_]*|\[[0-9]+\])*$

`dataPath` 指向的对象出错时

这个对象的错误只影响对应的图层,不会使整个响应无效。路径不存在、指向的不是对象、出现对象本身或该类型不支持的字段、字段值的类型或取值不合法、frame 缺少 width 或 height、远程图层没有 frame、远程点阵没有 content.pixels 时:

  • 编辑器图层回退到编辑器中保存的状态,App 在该图层的“数据路径”下方给出原因;
  • 远程图层不绘制;
  • 根点阵和其他图层照常显示。

数值超出字段表中列出的范围不算错误,渲染器会将其截断到可用范围。

示例
{
  "protocol": 1,
  "default": { "color": "#8EC8FB", "opacity": 0.06, "cornerRadius": 0.5 },
  "layout": { "gapMode": "far" },
  "pixels": [
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
    [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]
  ],
  "batch": [
    {
      "pixel": { "color": "#7EDDB5", "opacity": 1, "halo": 0.5 },
      "coordinates": [
        [7, 17]
      ]
    }
  ],
  "data": {
    "orders": {
      "title": {
        "frame": {
          "left": 0.07,
          "top": 0.12,
          "width": 0.6,
          "height": 0.16
        },
        "zIndex": 10,
        "content": { "text": "Orders today" },
        "style": {
          "color": "#A9C4E8",
          "fontSizeRatio": 0.1,
          "fontWeight": "500",
          "horizontalAlignment": "left"
        }
      },
      "total": {
        "frame": {
          "left": 0.07,
          "top": 0.32,
          "width": 0.6,
          "height": 0.4
        },
        "zIndex": 11,
        "content": { "text": 128 },
        "style": {
          "color": "#FFFFFF",
          "fontSizeRatio": 0.26,
          "fontWeight": "700",
          "horizontalAlignment": "left"
        }
      },
      "badge": {
        "frame": {
          "right": 0.07,
          "top": 0.14,
          "width": 0.24,
          "height": 0.2
        },
        "zIndex": 5,
        "style": {
          "gradientEnabled": true,
          "gradientColors": ["#2A63D4", "#56B9DD"],
          "cornerRadiusRatio": 1,
          "borderColor": "#D7F6FF",
          "borderOpacity": 0.46,
          "borderWidth": 1
        }
      },
      "trend": {
        "frame": {
          "right": 0.07,
          "top": 0.16,
          "width": 0.24,
          "height": 0.16
        },
        "zIndex": 6,
        "content": {
          "icon": "ph_trend_up",
          "iconCodePoint": 58542,
          "iconFont": "phosphorBold"
        },
        "style": { "color": "#FFFFFF" }
      }
    }
  },
  "layers": [
    {
      "id": "remote:orders-title",
      "type": "text",
      "dataPath": "data.orders.title"
    },
    {
      "id": "remote:orders-total",
      "type": "text",
      "dataPath": "data.orders.total"
    },
    {
      "id": "remote:badge",
      "type": "shape",
      "dataPath": "data.orders.badge"
    },
    {
      "id": "remote:trend",
      "type": "icon",
      "dataPath": "data.orders.trend"
    }
  ]
}
四个远程图层:两段文字、一个形状和一个图标

图层样式与内容#

dataPath 指向的对象通过 content 描述内容,通过 style 控制外观。以下按类型列出字段,content. / style. 前缀表示字段在该对象中的位置;颜色使用 #RRGGBB 或透明度在前的 #AARRGGBB,pt 为 iOS 逻辑像素。表中的默认值是远程图层省略字段时的取值;编辑器图层省略字段时沿用编辑器中的设置,编辑器新建图层的预设可能与这些默认值不同。

各类型图层通用的样式字段

此表适用于 text、image、shape,各自的 opacity 含义见对应类型的字段表。其他图层使用各自类型表中列出的样式字段。

style.backgroundColor
类型 / 取值Color
用途与规则填充图层背景区域的颜色。文本默认不显示背景,需提高 style.opacity;形状未指定此字段时使用 style.color。
style.cornerRadiusRatio
类型 / 取值0–1
用途与规则控制图层四角的弯曲程度,并沿此轮廓裁剪内容。半径 = 图层短边 × 此值 ÷ 2;0 是直角,1 是最大圆角;省略时为 0。正方形在 1 时成为圆,长方形成为胶囊。
style.borderColor
类型 / 取值Color
用途与规则描在图层轮廓内侧的边框颜色,默认白色。只有 borderWidth > 0 且 borderOpacity > 0 时可见。
style.borderOpacity
类型 / 取值0–1
用途与规则只控制边框可见度:0 隐藏,1 不额外降低颜色的透明度,默认 0。不会改变背景或内容的透明度。
style.borderWidth
类型 / 取值number · pt
用途与规则边框向内占用的宽度,单位 pt,默认 0。文本的可用区域也会向内缩进同样宽度;建议使用 0–8 pt,文本会将超出此范围的值截断。
style.gradientEnabled
类型 / 取值boolean
用途与规则是否用线性渐变替代纯色底色。API 省略时不启用;编辑器新建形状时通常会显式写入 true。
style.gradientColors
类型 / 取值Color[]
用途与规则按渐变方向依次排列的颜色,使用 2–3 个;首色在起点,末色在终点,中间色的位置由 gradientStops 决定。需同时启用 gradientEnabled。
style.gradientStops
类型 / 取值number[] · 0–1
用途与规则每个渐变色沿渐变线的位置,数量须与颜色一一对应。0 是起点,1 是终点,如 [0, 0.2, 1] 把中间色放在全程的 20% 处。使用递增值;省略或数量不符时均匀分布。
style.gradientAngle
类型 / 取值number · degrees
用途与规则只旋转背景渐变的方向,不旋转图层或内容,单位为度。0 从左向右,90 从上向下。API 省略时为 0;编辑器新建形状的预设为 135。
style.maskColor
类型 / 取值Color
用途与规则均匀叠加在图层内容上方的颜色,默认黑色。实际覆盖强度由 maskOpacity 控制;可用深色压暗,也可用其他颜色叠加色调。
style.maskOpacity
类型 / 取值0–0.6
用途与规则上述均匀遮罩的强度:0 不叠加,数值越大遮罩越明显,默认 0。它不直接降低原内容的透明度。
style.vignetteIntensity
类型 / 取值0–2
用途与规则控制图层四周边缘和四角的暗化程度,0 关闭,数值越大边缘越暗,中心相对保持明亮;默认 0。
style.readabilityGradient
类型 / 取值string
用途与规则从指定边缘向图层内部逐渐变透明的黑色渐变,用于衬托该处的叠加文字。none 关闭(默认);top、bottom、left、right 指定边缘,both 同时作用于上下两边,topLeftDiagonal、topRightDiagonal 从对应上角向对角方向渐隐。
通用样式剖解窄屏可横向滑动查看完整图纸 · 点击标注,查看对应部位
通用样式剖解虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。GLANCE / CHROME / DETAIL图层边界00.51frame.widthbackgroundColor · opacity1gradientColors · Stops · Angle2maskColor · maskOpacity3cornerRadiusRatio4borderWidth · Color · Opacity5readability · vignette6

虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。

text · 文本

  • 内容:content.text 是要显示的文字,可以是字符串,也可以是按原样显示的数字。编辑器图层未返回时,显示编辑器中填写的静态文本。
  • 样式:style 控制字形、字号和排版。背景、圆角、边框等使用本章通用样式字段。
content.text
类型 / 取值string · number
用途与规则要显示的文字。数字按原样转为文字,例如 128 显示为“128”;远程图层省略时为空字符串。
style.color
类型 / 取值Color
用途与规则文字颜色,默认白色;不会给背景着色。
style.textOpacity
类型 / 取值0–1
用途与规则只控制文字笔画的可见度,默认 1。0 隐藏文字,1 保留文字颜色原有的透明度;文字背景由 style.opacity 控制。
style.opacity
类型 / 取值0–1
用途与规则文字背景的透明度,默认 0;不是整个图层或文字本身的透明度。
style.fontSizeRatio
类型 / 取值0.02–0.28
用途与规则字号 = 整个内容画布的短边长度 × 此值,默认 0.12。例如画布短边为 160 pt,设为 0.1 得到 16 pt 字号;不是文本图层高度的 10%。
style.fontWeight
类型 / 取值string
用途与规则文字笔画的粗细,使用字符串 "300"、"400"、"500"、"600"、"700",依次更粗;默认 "400"。
style.fontFamily
类型 / 取值string
用途与规则选择文字字形:system 为系统比例字体(默认);systemMonospace 为系统等宽字体,适合计数或时间;monospace 使用 Menlo 等宽字体。
style.fontFamilyFallback
类型 / 取值string[]
用途与规则缺字时依次尝试的系统字体名称;不会从网络下载字体。
style.letterSpacing
类型 / 取值number · pt
用途与规则在正常排版的字距上增加的距离,单位 pt,iOS 默认 0。正值让文字更疏,负值更紧;不改变字号。
style.baselineRatio
类型 / 取值number
用途与规则可选的首行基线定位:基线距文字内容顶部的距离 = 字号 × 此值。用于把多个文本图层的文字基线对齐;省略时使用字体自然基线。
style.horizontalAlignment
类型 / 取值left / center / right
用途与规则文字在扣除内边距和边框后的可用区域内靠左、居中或靠右,默认 right;不会移动图层框。
style.verticalAlignment
类型 / 取值top / center / bottom
用途与规则文字在可用区域内靠上、居中或靠下,默认 top;不会修改 frame.top 或 frame.bottom。
style.autoWrap
类型 / 取值boolean
用途与规则是否按文本框可用宽度自动换行,默认 false;显式换行仍然保留,溢出内容会裁剪。
style.paddingRatio
类型 / 取值0–0.3
用途与规则每一侧的内边距 = 文本图层框短边长度 × 此值,默认 0;边框宽度再额外加到内边距上。数值越大,留给文字的区域越小。

文字或样式变化后,运行时按新的文字、字号、换行、内边距和边框计算所需的最小文本区域,并限制在内容画布内,避免主屏幕沿用旧区域裁字;这一计算不会改写 frame。

文本图层:文字与内容区域窄屏可横向滑动查看完整图纸 · 点击标注,查看对应部位
文本图层:文字与内容区域虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。GLANCE / TEXT / DETAIL图层边界GlanceAPI → 128frame.widthcontent.text1fontSizeRatio · fontWeight2paddingRatio · autoWrap3color · textOpacity4letterSpacing · baselineRatio5horizontal · verticalAlignment6

虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。

示例
{
  "protocol": 1,
  "pixels": [
    [
      { "empty": true }
    ]
  ],
  "data": {
    "parcels": {
      "frame": { "left": 0.08, "top": 0.22, "width": 0.84, "height": 0.56 },
      "content": { "text": 128 },
      "style": {
        "color": "#D9F2F7",
        "textOpacity": 1,
        "fontSizeRatio": 0.26,
        "fontWeight": "600",
        "fontFamily": "systemMonospace",
        "horizontalAlignment": "center",
        "verticalAlignment": "center",
        "autoWrap": false,
        "paddingRatio": 0,
        "backgroundColor": "#397DA0",
        "opacity": 0.3,
        "cornerRadiusRatio": 0,
        "borderColor": "#90BBCD",
        "borderOpacity": 0.6,
        "borderWidth": 1
      }
    }
  },
  "layers": [
    { "id": "remote:count", "type": "text", "dataPath": "data.parcels" }
  ]
}
数值、文字排版与背景

matrix · 点阵

  • 内容:content 与根点阵同构,由 pixels、default、batch、layout 组成,含义和规则与根点阵完全相同。真实网格的行列数由 pixels 决定。
  • 样式:点阵没有 style 字段。点的外观写在 content.default、batch 和 pixels 中,间距和留白写在 content.layout 中。
content.pixels
类型 / 取值(Pixel | null)[][]
用途与规则局部点阵内容,规则同根点阵的 pixels。远程点阵必填;编辑器点阵未返回时显示默认示例。
content.default
类型 / 取值Pixel
用途与规则缺省点样式。编辑器点阵会把它逐字段合并到编辑器设置的默认点样式上;远程点阵的基础值为 color #5EA2FF、opacity 0.82、cornerRadius 0.16。
content.batch
类型 / 取值{ pixel, coordinates }[]
用途与规则批量样式,规则同根点阵的 batch,必须与 content.pixels 一起返回。
content.layout
类型 / 取值MatrixLayout
用途与规则间距、单元宽高比与边缘留白,字段同“点阵布局”。编辑器点阵逐字段合并到编辑器设置上;未设置 gapMode 时为 near。
点阵图层:像素点与网格布局窄屏可横向滑动查看完整图纸 · 点击标注,查看对应部位
点阵图层:像素点与网格布局虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。GLANCE / MATRIX / DETAIL图层边界pixels[row][column]frame.widthcontent.pixels1color · opacity · halo2edgeInsetRatio3cellAspectRatio4columnGapRatio · rowGapRatio5cornerRadius · rotation6

虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。

优先级从高到低依次为:pixels 中的显式值,batch,响应中的 default / layout,编辑器中的 default / layout。编辑器中设置的行数、列数只用于默认示例:没有 pixels 或点阵无效时,渲染器按合并后的缺省样式生成一组稳定分布的示例,避免图层在 API 就绪前消失;有效的 pixels 不会被缩放或重排。

示例
{
  "protocol": 1,
  "pixels": [
    [
      { "empty": true }
    ]
  ],
  "data": {
    "title": {
      "frame": { "left": 0.06, "top": 0.08, "width": 0.88, "height": 0.14 },
      "content": { "text": "Contributions · 20 weeks" },
      "style": {
        "color": "#A9C4E8",
        "fontSizeRatio": 0.09,
        "fontWeight": "500",
        "horizontalAlignment": "left"
      }
    },
    "heatmap": {
      "frame": { "left": 0.06, "top": 0.28, "width": 0.88, "height": 0.64 },
      "content": {
        "default": { "color": "#FFFFFF", "opacity": 0.08, "cornerRadius": 0.25 },
        "layout": { "gapMode": "near" },
        "pixels": [
          [
            { "color": "#7EDDB5", "opacity": 0.85 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 0.7448688173552516 },
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.7545944628656934 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 0.9830690317402184 },
            null,
            null
          ],
          [
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 0.5229617408287728 },
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.9544462806264128 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 0.6555567507870917 },
            null,
            null,
            null
          ],
          [
            { "color": "#7EDDB5", "opacity": 0.7222294489865844 },
            null,
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.6638935382087501 },
            { "color": "#7EDDB5", "opacity": 0.6413972526463148 },
            null,
            null,
            null,
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.5311184461090914 },
            { "color": "#7EDDB5", "opacity": 0.8927628180779044 },
            { "color": "#7EDDB5", "opacity": 0.8698567704801822 },
            { "color": "#7EDDB5", "opacity": 0.5938312809225924 },
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.710199232267813 },
            { "color": "#7EDDB5", "opacity": 0.9951574673001937 },
            { "color": "#7EDDB5", "opacity": 0.974044818430527 }
          ],
          [
            null,
            { "color": "#7EDDB5", "opacity": 0.6708227479019796 },
            { "color": "#7EDDB5", "opacity": 0.9875732368676824 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 0.6668848538904473 },
            null,
            null,
            null,
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.5228328839421528 },
            { "color": "#7EDDB5", "opacity": 0.5214774850893487 },
            null,
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.7065983124568725 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 0.972886955341248 },
            null
          ],
          [
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 1 },
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.9993158218339733 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 0.7303804474628726 },
            null,
            null
          ],
          [
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 0.8229182097281214 },
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.6114321719061702 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 0.8256594886799811 },
            null,
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.7008502184288221 }
          ],
          [
            { "color": "#7EDDB5", "opacity": 0.5000626562032289 },
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.6949160968071824 },
            { "color": "#7EDDB5", "opacity": 0.8072480735714076 },
            { "color": "#7EDDB5", "opacity": 0.5647999972978959 },
            null,
            null,
            null,
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.6708958418347376 },
            { "color": "#7EDDB5", "opacity": 0.8120773109877517 },
            { "color": "#7EDDB5", "opacity": 0.6297695437501125 },
            null,
            null,
            { "color": "#7EDDB5", "opacity": 0.5926441641837852 },
            { "color": "#7EDDB5", "opacity": 0.9642279221859965 },
            { "color": "#7EDDB5", "opacity": 1 },
            { "color": "#7EDDB5", "opacity": 0.8892938715888167 }
          ]
        ]
      }
    }
  },
  "layers": [
    { "id": "remote:title", "type": "text", "dataPath": "data.title" },
    { "id": "remote:heatmap", "type": "matrix", "dataPath": "data.heatmap" }
  ]
}
局部热力图

curve · 曲线

  • 内容:content 声明采样点或函数,以及跟随曲线的标记。曲线的内容只来自 API:编辑器中的曲线图层只保存数据路径、初始位置与兜底样式。
  • 样式:style 控制描边、填充与绘图区内边距。

曲线内容:写在 dataPath 指向的对象的 content 中。

content.mode
类型 / 取值samples / function
用途与规则决定曲线的数据来源:samples 连接 points 中的采样点;function 在 domain 范围内计算 expression。有表达式时默认 function,否则为 samples。
content.points
类型 / 取值[x, y][]
用途与规则最多 1,024 个采样点,使用数值坐标对。
content.expression
类型 / 取值string · ≤512
用途与规则以 x 为自变量的受限数学表达式,支持 + - * / ^、括号、sin cos exp log abs sqrt min max、pi、e 和具名参数;不执行任意脚本。
content.parameters
类型 / 取值object · ≤64
用途与规则表达式中的具名数值参数,值限制在 ±1e9。
content.domain
类型 / 取值[min, max]
用途与规则横轴数据范围 [最小值, 最大值],分别映射到绘图区左、右边缘。省略时从采样点推导,无点时为 [0, 1]。
content.yDomain
类型 / 取值[min, max]
用途与规则纵轴显示范围 [最小值, 最大值],最小值对应绘图区底边,最大值对应顶边。例如 [0, 100] 的值 50 位于高度中点。省略时从采样点推导,无点时为 [0, 1]。
content.interpolation
类型 / 取值linear / stepAfter / monotone
用途与规则决定采样点之间的线形:linear 直接用直线连接,stepAfter 先保持前一个值再跳到后一个值,monotone 平滑连接并尽量避免过冲(默认)。
content.markers
类型 / 取值array · ≤32
用途与规则曲线上圆点与文字标记的数组;使用下表中的标记字段。

标记字段:写在每个 content.markers[] 对象中。

at.x
类型 / 取值number
用途与规则标记所在的横轴数据值,渲染器从曲线上计算对应高度;与 sampleIndex 择一。
at.sampleIndex
类型 / 取值integer
用途与规则标记跟随的采样点序号,从 0 开始,仅适合采样模式;优先使用按横轴递增排列的采样数组。
at.offsetPt
类型 / 取值[dx, dy] · −64–64
用途与规则标签文字相对曲线点的 [水平偏移, 垂直偏移],单位 pt,默认 [0, 0];正值分别向右、向下移动。只移动文字,不移动圆点或曲线。
symbol.shape
类型 / 取值circle
用途与规则目前绘制圆点标记,不支持任意形状。
symbol.radiusPt
类型 / 取值1–16
用途与规则圆点半径,单位 pt,默认 4。
symbol.fill
类型 / 取值Color
用途与规则圆点填充颜色,默认 #E6EDC9。
label
类型 / 取值string
用途与规则标记文字,可省略;它不是另一个可嵌套的文本图层。
labelStyle.color
类型 / 取值Color
用途与规则标签文字颜色,默认 #E6EEEE。
labelStyle.fontSizePt
类型 / 取值6–32
用途与规则标签字号,单位 pt,默认 10。
labelStyle.position
类型 / 取值top / bottom / left / right
用途与规则标签相对标记点的位置,默认 top。

曲线样式:写在 dataPath 指向的对象的 style 中。

style.color
类型 / 取值Color
用途与规则曲线描边的颜色;区域填充另用 fillColor。
style.opacity
类型 / 取值0–1
用途与规则曲线整体透明度,默认 1;也会乘到区域填充及标记的透明度上。
style.strokeWidth
类型 / 取值0.25–12 · pt
用途与规则曲线描边宽度,默认 2。
style.lineCap
类型 / 取值round / butt / square
用途与规则描边端点形状:round 在端点增加半圆(默认),butt 在坐标处平齐截断,square 以方头向外延伸半个线宽。
style.lineJoin
类型 / 取值round / bevel / miter
用途与规则折点处两段线的连接形状:round 圆角(默认),bevel 削平尖角,miter 保留尖角。主要在折线或阶梯曲线上明显。
style.dashLength
类型 / 取值0.5–64 · pt
用途与规则虚线实段长度;省略为实线。
style.dashGap
类型 / 取值0–64 · pt
用途与规则虚线间隔,默认 4,只在使用虚线时生效。
style.fillColor
类型 / 取值Color
用途与规则曲线到绘图区底边之间的区域填充颜色,省略时使用描边颜色。
style.fillOpacity
类型 / 取值0–1
用途与规则区域填充自身的透明度,默认 0(不填充)。最终还会乘 style.opacity;不会改变描边粗细或透明度。
style.plotPadding
类型 / 取值0–48 · pt
用途与规则图层框四边到内部绘图区的距离,单位 pt,默认 0。数值越大,曲线可用宽高越小;数据坐标仍按 domain / yDomain 映射到缩小后的绘图区。
曲线图层:数据坐标与绘制区域窄屏可横向滑动查看完整图纸 · 点击标注,查看对应部位
曲线图层:数据坐标与绘制区域虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。GLANCE / CURVE / DETAIL图层边界010100Nowframe.widthdomain · yDomain1points · interpolation2fillColor · fillOpacity3markers · symbol · label4strokeWidth · lineCap · lineJoin5plotPadding6

虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。

这些标记只绘制圆点和文字,不会自动生成坐标轴。使用 [x, y] 采样点、label 和 labelStyle.position 可保持 App 与主屏幕兼容;图片或图标标记请用独立图层组合。

示例
{
  "protocol": 1,
  "pixels": [
    [
      { "empty": true }
    ]
  ],
  "data": {
    "activity": {
      "frame": { "left": 0.05, "top": 0.08, "width": 0.9, "height": 0.84 },
      "content": {
        "mode": "samples",
        "points": [
          [0, 30],
          [2, 18],
          [4, 65],
          [6, 45],
          [8, 90],
          [10, 70]
        ],
        "domain": [0, 10],
        "yDomain": [0, 100],
        "interpolation": "linear",
        "markers": [
          {
            "at": { "x": 8 },
            "symbol": { "shape": "circle", "radiusPt": 4, "fill": "#E1EEE0" },
            "label": "Now",
            "labelStyle": {
              "color": "#E1EEE0",
              "fontSizePt": 9,
              "position": "top"
            }
          }
        ]
      },
      "style": {
        "color": "#A7DAD7",
        "opacity": 1,
        "strokeWidth": 2,
        "lineCap": "round",
        "lineJoin": "round",
        "fillColor": "#77B6BB",
        "fillOpacity": 0.22,
        "plotPadding": 8
      }
    }
  },
  "layers": [
    {
      "id": "remote:activity",
      "type": "curve",
      "dataPath": "data.activity"
    }
  ]
}
采样点、区域填充与曲线标记

image · 图片

  • 内容:content.url 指定图片,可以是 HTTPS 地址、data:image/…;base64, 或原始 Base64 字符串。
  • 样式:URL 图片按 cover 等比填满图层框,超出部分裁掉。圆角、边框和遮罩使用本章通用字段;编辑器上传的本地图片按 contain 完整显示。
content.url
类型 / 取值string
用途与规则图片地址或 Base64 数据。编辑器图片图层的来源选择“API 数据”时,从 dataPath 指向的对象读取此字段;给出 url 时,图层显示这张图片。服务端不能引用设备上的文件路径。
style.opacity
类型 / 取值0.1–1
用途与规则控制图片本身的可见度,默认 1。0.5 表示图片以一半不透明度绘制,透出下面的内容;当前最小为 0.1。它不改变上方遮罩或边框的透明度。
style.color
类型 / 取值Color
用途与规则图片加载中的占位颜色;不是图片染色。
图片图层:填充、裁剪与遮罩窄屏可横向滑动查看完整图纸 · 点击标注,查看对应部位
图片图层:填充、裁剪与遮罩虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。GLANCE / IMAGE / DETAIL图层边界frame.widthcontent.url1frame → cover crop2opacity · maskOpacity3cornerRadiusRatio · borderWidth4vignetteIntensity5readabilityGradient6

虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。

主屏幕远程图片需返回 image/*,最大 6 MB,并缩略到最长边 1,200 px。Base64 解码上限 4 MB,但内嵌数据仍受整个 JSON 响应 512 KB 的限制。

icon · 图标

  • 内容:内置图标用 content.icon、content.iconCodePoint、content.iconFont 配套声明同一个图标;图片图标用 content.url。同一个对象只能给出其中一种。
  • 样式:图标等比完整放入 frame,由 textOpacity 控制透明度;字形颜色及发光使用下表字段。
content.icon
类型 / 取值string
用途与规则图标库中的稳定名称,如 ph_activity,供 App 预览查找图标。它与下两个字段标识同一个图标,应配套填写;不是与编码二选一。编辑器图层收到 icon 后,不再沿用编辑器中保存的码点和字体。
content.iconCodePoint
类型 / 取值integer
用途与规则图标在 iconFont 指定字体中的 Unicode 码点,主屏幕按此值绘制字形。例如 ph_activity 为 57344;不是列表序号。必须与 icon 一起返回;缺少时主屏幕仅能按部分旧版 Material 名称回退,不能覆盖当前图标库。
content.iconFont
类型 / 取值phosphorBold / devicon / simpleIcons / material
用途与规则主屏幕使用的内置字体标识,必须与 icon、iconCodePoint 一起返回。例如 ph_activity 对应 phosphorBold;同一码点在不同字体中可表示不同图形。此字段不加载远程字体。
content.url
类型 / 取值string
用途与规则图片图标的地址或 Base64 数据,按 contain 完整显示;不能与 content.icon 同时返回。编辑器图标图层的来源选择“API 数据”时,该对象可以返回内置图标,也可以返回 url。
style.color
类型 / 取值Color
用途与规则内置字形的笔画或填充颜色,默认白色;不会给图片图标染色。
style.textOpacity
类型 / 取值0–1
用途与规则图标整体透明度,默认 1。字形和图片图标都使用此值,0 隐藏图标。
style.iconGlowEnabled
类型 / 取值boolean
用途与规则启用发光,默认 false;用于内置字形及编辑器上传的本地 SVG,不用于远程图片图标。
style.iconGlowColor
类型 / 取值Color
用途与规则图标周围模糊光晕的颜色,不改变字形本身的颜色;省略时使用图标颜色。需启用 iconGlowEnabled。
style.iconGlowOpacity
类型 / 取值0–1
用途与规则光晕自身的透明度,默认 0.65;数值越大光越明显。图标整体的 textOpacity 还会影响最终发光可见度。
style.iconGlowRadius
类型 / 取值0.01–0.16
用途与规则发光模糊范围相对于图标短边的比例,默认 0.07。数值越大,光越分散、覆盖范围越大;不会放大图标字形。

在独立工具页按 App 的分类和顺序浏览、搜索图标,查看对应的 icon、iconCodePoint 和 iconFont,实时调整样式并复制图层 JSON。 打开图标查看与预览

图标图层:字形、尺寸与发光窄屏可横向滑动查看完整图纸 · 点击标注,查看对应部位
图标图层:字形、尺寸与发光虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。GLANCE / ICON / DETAIL图层边界frame.widthicon · codePoint · font1color · textOpacity2frame → contain3iconGlowEnabled · Color4iconGlowRadius5iconGlowOpacity6

虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。

主屏幕远程图片图标最大 1 MB,缩略到最长边 512 px。编辑器上传的本地图标由编辑器管理。

示例
{
  "protocol": 1,
  "pixels": [
    [
      { "empty": true }
    ]
  ],
  "data": {
    "icons": [
      {
        "frame": {
          "left": 0.1,
          "top": 0.25,
          "width": 0.2,
          "height": 0.5
        },
        "content": {
          "icon": "ph_activity",
          "iconCodePoint": 57344,
          "iconFont": "phosphorBold"
        },
        "style": { "color": "#A7DAD7", "textOpacity": 1 }
      },
      {
        "frame": {
          "left": 0.4,
          "top": 0.25,
          "width": 0.2,
          "height": 0.5
        },
        "content": {
          "icon": "ph_lightning",
          "iconCodePoint": 58078,
          "iconFont": "phosphorBold"
        },
        "style": { "color": "#F0C778", "textOpacity": 1 }
      },
      {
        "frame": {
          "left": 0.7,
          "top": 0.25,
          "width": 0.2,
          "height": 0.5
        },
        "content": {
          "icon": "ph_trend_up",
          "iconCodePoint": 58542,
          "iconFont": "phosphorBold"
        },
        "style": { "color": "#A7DAD7", "textOpacity": 0.45 }
      }
    ]
  },
  "layers": [
    {
      "id": "remote:activity",
      "type": "icon",
      "dataPath": "data.icons[0]"
    },
    {
      "id": "remote:lightning",
      "type": "icon",
      "dataPath": "data.icons[1]"
    },
    {
      "id": "remote:trend",
      "type": "icon",
      "dataPath": "data.icons[2]"
    }
  ]
}
不同字形、颜色与透明度

line · 直线

  • 内容:content.direction 选择横线或竖线,线条穿过图层框中心;其他角度使用对象的 rotation。
  • 样式:frame 决定摆放位置和长度,strokeWidth 决定粗细,pattern 决定实线、虚线或点线。
content.direction
类型 / 取值horizontal / vertical
用途与规则直线方向,默认水平;横线位于图层框的垂直中心,竖线位于水平中心。
style.color
类型 / 取值Color
用途与规则实线、虚线或点线的颜色,默认白色;启用渐变时改用 gradientColors。
style.opacity
类型 / 取值0–1
用途与规则整条直线的透明度,默认 1;同时作用于渐变色和点线圆点。
style.strokeWidth
类型 / 取值0.5–8 · pt
用途与规则直线宽度,默认 2;图层框决定长度,而不是粗细。
style.pattern
类型 / 取值solid / dashed / dotted
用途与规则线条绘制方式:solid 连续实线(默认);dashed 重复绘制实段与空隙;dotted 重复绘制圆点,圆点直径由 strokeWidth 决定。
style.cap
类型 / 取值round / butt
用途与规则实线及虚线实段的端点形状:round 为半圆端点(默认),butt 在端点处平齐结束。点线固定使用圆点,不受此字段影响。
style.dashLength
类型 / 取值1–32 · pt
用途与规则虚线每一实段的长度,默认 6,仅 dashed 使用。
style.dashGap
类型 / 取值0–32 · pt
用途与规则相邻虚线实段或圆点之间的留白长度,单位 pt,默认 4。数值越大线越稀疏,solid 模式下不使用。
style.gradientEnabled
类型 / 取值boolean
用途与规则用渐变颜色绘制直线,默认 false。
style.gradientColors
类型 / 取值Color[]
用途与规则2–3 个依次分布的渐变色。需启用 gradientEnabled;原生主屏幕按图层框从左到右渐变,App 的竖线预览则按从上到下渐变。
style.gradientStops
类型 / 取值number[] · 0–1
用途与规则各颜色对应的位置,0 为起点,1 为终点;数量须与颜色相同并递增,省略时均匀分布。
直线图层:线宽、虚线与端点窄屏可横向滑动查看完整图纸 · 点击标注,查看对应部位
直线图层:线宽、虚线与端点虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。GLANCE / LINE / DETAIL图层边界dashgapframe.widthdirection · frame1strokeWidth2pattern · dashLength · dashGap3cap4gradientColors · gradientStops5color · opacity6

虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。

示例
{
  "protocol": 1,
  "pixels": [
    [
      { "empty": true }
    ]
  ],
  "data": {
    "solid": {
      "frame": { "left": 0.1, "top": 0.32, "width": 0.8, "height": 0.04 },
      "content": { "direction": "horizontal" },
      "style": {
        "color": "#A4DAE3",
        "opacity": 0.55,
        "strokeWidth": 1,
        "pattern": "solid",
        "cap": "butt"
      }
    },
    "dashed": {
      "frame": { "left": 0.1, "top": 0.62, "width": 0.8, "height": 0.04 },
      "content": { "direction": "horizontal" },
      "style": {
        "color": "#A4DAE3",
        "opacity": 1,
        "strokeWidth": 3,
        "pattern": "dashed",
        "cap": "butt",
        "dashLength": 8,
        "dashGap": 6
      }
    }
  },
  "layers": [
    { "id": "remote:solid", "type": "line", "dataPath": "data.solid" },
    { "id": "remote:dashed", "type": "line", "dataPath": "data.dashed" }
  ]
}
实线与虚线的线宽、间距对照

shape · 形状

  • 内容:图层本身就是圆角矩形,不需要 content;适合作为底板、徽章或进度条轨道。
  • 样式:用 style 指定填充和边框,圆角、渐变及遮罩使用本章通用字段。渐变和边框需显式启用或设置可见值。
content
类型 / 取值object
用途与规则无需声明内容值,图层本身即一个可填充、带边框的圆角矩形。
style.color
类型 / 取值Color
用途与规则形状的纯色填充,默认 #2A63D4。存在 backgroundColor 时后者优先;启用渐变后由 gradientColors 决定填充颜色。
style.opacity
类型 / 取值0–1
用途与规则只控制形状内部填充的透明度,默认 1。0 隐藏填充但仍可保留边框,边框透明度另由 borderOpacity 控制。
形状图层:填充、圆角与边框窄屏可横向滑动查看完整图纸 · 点击标注,查看对应部位
形状图层:填充、圆角与边框虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。GLANCE / SHAPE / DETAIL图层边界00.51frame.widthcolor · backgroundColor · opacity1gradientEnabled · gradientColors2gradientStops · gradientAngle3cornerRadiusRatio4borderWidth5borderColor · borderOpacity6

虚线为边界或辅助线,尺寸线仅作字段说明;图层本身不会绘制这些标记。

示例
{
  "protocol": 1,
  "pixels": [
    [
      { "empty": true }
    ]
  ],
  "data": {
    "badge": {
      "frame": { "left": 0.12, "top": 0.22, "width": 0.76, "height": 0.56 },
      "style": {
        "opacity": 1,
        "cornerRadiusRatio": 1,
        "gradientEnabled": true,
        "gradientColors": ["#225B80", "#78B6BA"],
        "gradientStops": [0, 1],
        "gradientAngle": 0,
        "borderColor": "#BCE3E4",
        "borderOpacity": 0.9,
        "borderWidth": 2
      }
    }
  },
  "layers": [
    { "id": "remote:badge", "type": "shape", "dataPath": "data.badge" }
  ]
}
胶囊形状的渐变填充与独立边框

服务端整图渲染#

除了用点阵和图层描述内容,你也可以让服务端完全接管绘制:用熟悉的图表库、模板引擎或无头浏览器,把整张小组件画面渲染成一张图片,再通过 data 返回。小组件把它作为「图片」材质铺满整个画布,不需要配置任何图层,也不必学习本页的绘制语法。

适合这些场景:已有成熟的报表或图片渲染管线;需要复杂图表、特殊字体或自由排版;希望由服务端一处控制全部视觉,随时调整而无需改动 App 中的配置。

在 App 中设置

  • 在编辑页把表面材质设为「图片」;
  • 图片来源选择「API」;
  • 数据路径填写图片所在的字段,例如 data.cover;
  • 可按需开启可读性渐变,方便在图片上叠加文字图层。

响应

只返回一张图片
{
  "protocol": 1,
  "pixels": [[{ "empty": true }]],
  "data": {
    "cover": "https://cdn.example.com/widgets/orders-medium@3x.png"
  }
}
HTTPS 地址
返回 image/*,最大 6 MB;主屏幕会将其缩略到最长边 1,200 px。
data:image/…;base64, 或原始 Base64
直接内嵌在响应中,适合小图;整个 JSON 响应仍受 512 KB 限制。

这里的数据路径属于材质设置,直接指向图片字符串;它不是图层,不需要写成对象。

图片按 cover 等比铺满整个小组件,超出部分裁掉。请按请求参数 gw_canvas_width_pt × gw_canvas_height_pt 的宽高比出图,并以 2–3 倍像素绘制,以保证在主屏幕上清晰。

pixels 仍然必填,返回 [[{"empty": true}]] 即可只显示图片。图片之上依旧可以叠加点阵或图层,例如用原生文字显示需要随时更新的数值。
图片中的文字不会随系统字体、粗体文本等辅助功能设置变化。如果图片地址不变而内容会更新,建议在地址中加入版本号或时间戳,避免取到缓存中的旧图。

请求签名#

可以在 App 中为小组件添加密钥,使每个请求都携带两个可供你服务器验证的请求头,用于证明请求的确是来自 Glance Widgets 小组件,而不是无关或恶意的第三方。密钥本身永远不会被发送。

X-GlanceWidgets-Timestamp
Unix 时间,单位为毫秒,以十进制字符串表示。
X-GlanceWidgets-Signature
Base64(HMAC-SHA256(key = secret, message = timestamp + "\n" + secret)),全程使用 UTF-8。
请求头使用当前产品线路标识 GlanceWidgets。签名只覆盖时间戳与密钥,不包含 URL、查询参数或请求体。

在服务器端:拒绝过期的时间戳(例如 ±5 分钟),重新计算签名,并以恒定时间进行比较。

verify.ts
import crypto from 'node:crypto'

const SECRET = process.env.GLANCE_SECRET          // same value as in the app
const WINDOW_MS = 5 * 60 * 1000

export function verify(req) {
  const ts = req.get('X-GlanceWidgets-Timestamp')
  const sig = req.get('X-GlanceWidgets-Signature')
  if (!ts || !sig || Math.abs(Date.now() - Number(ts)) > WINDOW_MS) return false

  const expected = crypto
    .createHmac('sha256', SECRET)
    .update(`${ts}\n${SECRET}`)
    .digest('base64')

  const a = Buffer.from(sig)
  const b = Buffer.from(expected)
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}
verify.py
import base64, hashlib, hmac, os, time

SECRET = os.environ["GLANCE_SECRET"]
WINDOW_MS = 5 * 60 * 1000

def verify(headers) -> bool:
    ts = headers.get("X-GlanceWidgets-Timestamp")
    sig = headers.get("X-GlanceWidgets-Signature")
    if not ts or not sig or abs(time.time() * 1000 - int(ts)) > WINDOW_MS:
        return False
    message = f"{ts}\n{SECRET}".encode()
    expected = base64.b64encode(
        hmac.new(SECRET.encode(), message, hashlib.sha256).digest()
    ).decode()
    return hmac.compare_digest(sig, expected)

测试向量:密钥 this is secret,时间戳 1700000000000 → sSFWELbV2YwjdDQhWZwTcWlX5BWUx5J6TPpsZmuPii0=。

限制与错误#

响应体大小
512 KB (524,288 bytes)
根点阵
rows × columns ≤ 4,096;≥ 1 × 1;矩形
图层声明
每条只含 id、type、dataPath,id 以 remote: 为前缀
协议
1 或省略
曲线
≤ 1,024 个点 · ≤ 32 个标记 · 表达式 ≤ 512 个字符
图片
≤ 6 MB 远程 · ≤ 4 MB Base64 · cover 填充

响应体超限、根点阵尺寸无效、batch 坐标越界、图层声明结构错误等,会使 App 拒绝整个响应。dataPath 指向的对象出错只影响对应的图层:编辑器图层回退到保存的状态,远程图层不绘制。曲线采样、标记、参数超出数量上限时只取预算内的部分;超长或无效表达式不会执行。

刷新#

主屏幕小组件按 WidgetKit 时间线请求新画面,大约每 15 分钟一次。具体时刻由 iOS 根据电量、使用情况与系统的刷新预算决定。请让画面在两次更新之间依然有意义;如有需要,可在 data 中加入「最后更新」时间。

在线调试#

编辑 JSON,实时查看渲染结果。校验器采用与 App 相同的限制和优先级。

画面有效 0 个单元 · 0 个图层 · 0 字节

检查清单#

  • HTTPS 接口,在数秒内返回 2xx。
  • 根为带有 "protocol": 1 的对象,以及不超过 4,096 个单元的矩形 pixels 数组。
  • 颜色为 #RRGGBB(或 ARGB 形式的 #AARRGGBB)。
  • layers 每条只含 id、type、dataPath,id 以 remote: 开头。
  • 每个 dataPath 都指向 data 中的一个对象;远程图层的对象带有含 width、height 的 frame。
  • 点阵根据 gw_aspect_ratio 确定大小,而不是使用固定表格。
  • 若启用了签名,请校验时间窗口,并以恒定时间验证签名。