由你的 API 驱动的实时小组件

每一次关心的变化,都一眼可见。

Glance Widgets 将任意 HTTPS API 变成主屏幕上实时、精美的小组件。点阵、文字、曲线、图片与 Liquid Glass,由一份 JSON 响应组合而成。

次 API 请求
1
次 API 请求
种内容表达
种内容表达
种小组件材质, 含 Liquid Glass
6
种小组件材质, 含 Liquid Glass
个中转服务器, 守护你的隐私
0
个中转服务器, 守护你的隐私
9:41

案例

任意业务,任意样式。

下方每个小组件,都由一份数据实时绘制——你的 API 返回什么,小组件就呈现什么。 选一个,看看它背后的数据。

发布监控

部署之后的请求矩阵、副本健康度与 P95。

大 · ambient
背后的数据 · JSON
{
  "protocol": 1,
  "pixels": [
    [
      { "empty": true }
    ]
  ],
  "data": {
    "icon": {
      "frame": {
        "left": 0.07,
        "top": 0.065,
        "width": 0.07,
        "height": 0.07
      },
      "zIndex": 2,
      "content": {
        "icon": "ph_rocket",
        "iconCodePoint": 58366,
        "iconFont": "phosphorBold"
      },
      "style": { "color": "#8EC8FB" }
    },
    "service": {
      "frame": { "left": 0.16, "top": 0.06, "width": 0.8, "height": 0.08 },
      "zIndex": 2,
      "content": { "text": "Checkout · v4.12.0" },
      "style": {
        "color": "#FFFFFF",
        "fontWeight": "600",
        "horizontalAlignment": "left",
        "verticalAlignment": "center",
        "fontSizeRatio": 0.05
      }
    },
    "state": {
      "frame": { "left": 0.07, "top": 0.15, "width": 0.86, "height": 0.07 },
      "zIndex": 2,
      "content": { "text": "Deployed 14:20 · watching" },
      "style": {
        "color": "#8EA3C4",
        "fontWeight": "500",
        "horizontalAlignment": "left",
        "verticalAlignment": "top",
        "fontSizeRatio": 0.038
      }
    },
    "requests": {
      "frame": { "left": 0.07, "top": 0.27, "width": 0.86, "height": 0.38 },
      "zIndex": 1,
      "content": {
        "default": { "color": "#FFFFFF", "opacity": 0.06, "cornerRadius": 0.3 },
        "layout": { "gapMode": "near", "cellAspectRatio": 0.9 },
        "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,
            { "color": "#8EC8FB", "opacity": 0.9500000000000001 },
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            { "color": "#8EC8FB", "opacity": 0.9500000000000001 },
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null
          ],
          [
            null,
            null,
            null,
            null,
            null,
            { "color": "#8EC8FB", "opacity": 0.9 },
            { "color": "#8EC8FB", "opacity": 0.9 },
            { "color": "#8EC8FB", "opacity": 0.9 },
            { "color": "#8EC8FB", "opacity": 0.9 },
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            { "color": "#8EC8FB", "opacity": 0.9 },
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null,
            null
          ],
          "… 6 more"
        ]
      }
    },
    "rule": {
      "frame": { "left": 0.07, "top": 0.7, "width": 0.86, "height": 0.02 },
      "zIndex": 1,
      "content": { "direction": "horizontal" },
      "style": {
        "color": "#FFFFFF",
        "opacity": 0.16,
        "strokeWidth": 1,
        "pattern": "dotted"
      }
    },
    "replicasLabel": {
      "frame": { "left": 0.07, "top": 0.75, "width": 0.28, "height": 0.06 },
      "zIndex": 2,
      "content": { "text": "Replicas" },
      "style": {
        "color": "#8EA3C4",
        "fontWeight": "500",
        "horizontalAlignment": "left",
        "verticalAlignment": "top",
        "fontSizeRatio": 0.034
      }
    },
    "errorsLabel": {
      "frame": { "left": 0.37, "top": 0.75, "width": 0.28, "height": 0.06 },
      "zIndex": 2,
      "content": { "text": "Error rate" },
      "style": {
        "color": "#8EA3C4",
        "fontWeight": "500",
        "horizontalAlignment": "left",
        "verticalAlignment": "top",
        "fontSizeRatio": 0.034
      }
    },
    "p95Label": {
      "frame": { "left": 0.67, "top": 0.75, "width": 0.28, "height": 0.06 },
      "zIndex": 2,
      "content": { "text": "P95" },
      "style": {
        "color": "#8EA3C4",
        "fontWeight": "500",
        "horizontalAlignment": "left",
        "verticalAlignment": "top",
        "fontSizeRatio": 0.034
      }
    },
    "replicas": {
      "frame": { "left": 0.07, "top": 0.82, "width": 0.28, "height": 0.12 },
      "zIndex": 2,
      "content": { "text": "6/6" },
      "style": {
        "color": "#7EDDB5",
        "fontWeight": "700",
        "horizontalAlignment": "left",
        "verticalAlignment": "top",
        "fontSizeRatio": 0.075
      }
    },
    "errors": {
      "frame": { "left": 0.37, "top": 0.82, "width": 0.28, "height": 0.12 },
      "zIndex": 2,
      "content": { "text": "0.02%" },
      "style": {
        "color": "#FFFFFF",
        "fontWeight": "700",
        "horizontalAlignment": "left",
        "verticalAlignment": "top",
        "fontSizeRatio": 0.075
      }
    },
    "p95": {
      "frame": { "left": 0.67, "top": 0.82, "width": 0.28, "height": 0.12 },
      "zIndex": 2,
      "content": { "text": "183 ms" },
      "style": {
        "color": "#FFFFFF",
        "fontWeight": "700",
        "horizontalAlignment": "left",
        "verticalAlignment": "top",
        "fontSizeRatio": 0.075
      }
    }
  },
  "layers": [
    { "id": "remote:icon", "type": "icon", "dataPath": "data.icon" },
    { "id": "remote:service", "type": "text", "dataPath": "data.service" },
    { "id": "remote:state", "type": "text", "dataPath": "data.state" },
    {
      "id": "remote:requests",
      "type": "matrix",
      "dataPath": "data.requests"
    },
    { "id": "remote:rule", "type": "line", "dataPath": "data.rule" },
    {
      "id": "remote:replicasLabel",
      "type": "text",
      "dataPath": "data.replicasLabel"
    },
    {
      "id": "remote:errorsLabel",
      "type": "text",
      "dataPath": "data.errorsLabel"
    },
    { "id": "remote:p95Label", "type": "text", "dataPath": "data.p95Label" },
    { "id": "remote:replicas", "type": "text", "dataPath": "data.replicas" },
    { "id": "remote:errors", "type": "text", "dataPath": "data.errors" },
    { "id": "remote:p95", "type": "text", "dataPath": "data.p95" }
  ]
}

工作原理

返回一份 JSON,剩下的交给我们。

Glance Widgets 负责校验、绑定数据并原生绘制,再随系统的刷新节奏保持更新。

01 · 请求HTTPS

请求

小组件携带尺寸类型、画布大小与宽高比请求你的 HTTPS 接口,让你为真实的空间而绘制。

GET https://api.acme.dev/widget
  ?gw_protocol=1
  &gw_platform=ios
  &gw_family=small
  &gw_canvas_width_pt=158.00
  &gw_canvas_height_pt=158.00
  &gw_aspect_ratio=1.0000
  &gw_context=app_preview
02 · 响应200 · application/json

响应

返回一个点阵,再按需叠加文字、曲线、图片、图标、线条与形状,繁简随心。

{
  "protocol": 1,
  "default": { "color": "#8EC8FB", "opacity": 0.07 },
  "pixels": [[null, null, …], …],
  "batch": [{ "pixel": { "color": "#5F9CF0" },
              "coordinates": [[12, 0], …] }],
  "data": { "api": { "latency": {
    "frame": { "left": 0.09, "top": 0.19, … },
    "content": { "text": "170 ms" }, …
  } } },
  "layers": [{ "id": "remote:latency", "type": "text",
               "dataPath": "data.api.latency" }]
}
03 · 屏幕呈现实时

渲染

App 校验并规范化画面,再由 WidgetKit 呈现在主屏幕、待机显示等位置。

能力

方寸画布,容得下几乎任何想法。

该强大的地方足够强大,该克制的地方足够克制。灵活的点阵与扁平图层系统,从一盏状态灯到完整看板,都能承载。

用像素,画出自己的语言。

点阵可以表达任意内容。逐点设置颜色、透明度、圆角、旋转与光晕,从锐利的 LED 面板到柔和的像素画。

cornerRadiusrotationhaloopacity

七种图层类型

文字、曲线、图片、图标、线条、形状与本地点阵。扁平、按层级排序,以相对坐标定位。

matrix
text
curve
image
icon
line
shape

更多外观选择

Liquid Glass、透明玻璃、纯色、渐变、环境光与图片,让小组件与系统浑然一体。

Liquid Glass
Glass
Solid
Gradient
Ambient
Image

数据绑定

用 data.orders.total 这样的路径,让任意图层指向你返回的一个对象,位置、内容与样式都从这里读取。没有模板,没有需要调试的表达式。

"dataPath": "data.orders.total"112

你来画,它只负责展示。

完全不必了解 Glance Widgets 的内容语法。用你熟悉的语言、图表库或无头浏览器,在自己的服务器上把实时画面渲染成图片,直接返回即可,再在 App 中把材质设为“图片”。Glance Widgets 就成了呈现你内容的窗口——学习成本最低,自由度最高。

零语法学习任意语言与工具URL 或 Base64
了解整图渲染

由系统调度刷新

小组件按 WidgetKit 时间线重新请求。无需托管,无需推送。

隐私,从设计开始

请求从设备直达你的服务器,可选 HMAC 签名。我们从不中转、代理,也看不到你的数据。

每种尺寸,包括待机显示。

小、中、大三种尺寸,每一种都会被告知以点(pt)为单位的精确画布。

动手一改,立刻可见。

在可视化编辑器中拖动、缩放并设置本地图层样式,以真实主屏幕尺寸预览。

面向开发者

也可以,把绘制交给你的服务器。

只要能返回 JSON,就能发布为小组件。任何语言、技术栈、托管方式:定时任务、无服务器函数,或你的生产 API。

  • 普通的 HTTPS GET,画布信息在查询参数中
  • 严谨、有文档的协议,限制清晰明确
  • 不想学协议?直接返回服务端渲染好的整张图片
  • 可选的 HMAC-SHA256 请求签名
  • 渲染效果与 App 一致的浏览器 Playground
server.ts
import express from 'express'

const app = express()

app.get('/widget', async (req, res) => {
  // The widget tells you exactly how much space it has.
  const family = req.query.gw_family          // small | medium | large
  const orders = await db.orders.today()

  res.json({
    protocol: 1,
    default: { color: '#8EC8FB', opacity: 0.08, cornerRadius: 0.5 },
    pixels: Array.from({ length: 8 }, () => Array(20).fill(null)),
    data: {
      // Where the layer sits, what it shows, how it looks.
      total: {
        frame: { left: 0.08, top: 0.3, width: 0.84, height: 0.4 },
        content: { text: orders.count },
        style: { fontSizeRatio: 0.24, fontWeight: '700', horizontalAlignment: 'left' },
      },
    },
    // Declare a layer and point it at its object.
    layers: [{ id: 'remote:total', type: 'text', dataPath: 'data.total' }],
  })
})

app.listen(3000)
{ }主流语言的 SDK 内置像素模板、点阵字体与图表,你只需描述想要的效果,而不是二维数组。

隐私

你的数据,留在你的掌控中。

核心功能在你的设备上运行。已签名的请求直达你的服务器,Glance Widgets 从不中转、代理或存储你展示的内容。

Pro

每个方案,皆含全部 Pro 功能。

各方案均享有完整Pro功能,仅订阅时长不同。今后上线的新平台与新功能,也无需额外付费。

早鸟价进行中调价计划
获取 Glance Widgets

所有方案均包含

  • 不限数量的 API 驱动小组件
  • 全部七种图层类型
  • Liquid Glass、玻璃、渐变、环境光与图片材质
  • 使用你自己的密钥进行请求签名
  • 小、中、大尺寸与待机显示
  • 加密备份
  • 未来新平台与新功能,上线即享

以上为中国大陆价格,仅供参考,实际以 App 内订阅时显示的价格为准。不同国家或地区的价格会因汇率、物价等因素有所差异。

订阅制方案均可免费试用 7 天,之后按所选方案自动续订,可在 Apple 账户中取消。

提供免费版。

可使用基础功能,想让更多内容出现在主屏上时,再选择 Pro。

免费版也可以完整编辑和预览全部 Pro 能力。

功能免费版Pro
创建小组件5 个 不限
主屏幕显示1 个 不限
单个组件图层8 层 不受免费版限制
卡片风格基础风格 全部风格
StandBy 支持
备份与迁移 支持

接下来

你所关心的,出现在更多屏幕上。

灵动岛

即将推出

实时状态,就在你视线所及之处。

Apple Watch

即将推出

你的画面,落在腕间。

iPadOS 与 macOS

即将推出

更大的画布,同一套协议。

网页编辑器

即将推出

在网页上设计并预览小组件。

跨设备同步

即将推出

通过在线账号与 iCloud,让你的小组件出现在每台设备上。

社区模板

即将推出

发现,创作,分享。

宏与快捷指令

即将推出

为小组件的指定区域绑定动作:轻点打开网页,或运行预先设置的快捷指令。

调价计划

早鸟价格计划

Glance Widgets 以早鸟价起步,价格会随着功能的完善分阶段上调。

返回方案
  1. 01

    早鸟价

    当前阶段

    首发价格,持续到第二阶段开始

  2. 02

    第二阶段

    跨设备同步、灵动岛、Apple Watch、网页编辑器等功能陆续上线后

  3. 03

    正式价

    iPadOS、macOS、模板库、宏与快捷指令等功能补全后

  • 加入时的价格,保留到正式价生效满一年
  • 每次调价前,至少提前 2 周公告
  • 现在购买,以更低的早鸟价终身购买。

取消、换方案或中断订阅后,不再保留原价。已支付的订阅周期会完整履行。

常见问题

你想知道的,都在这里。

要展示实时数据,你需要一个返回 JSON 的 HTTPS 接口,无服务器函数或一段脚本都可以。不接入 API 时,可视化编辑器也能让你组合静态文字、图片、形状与像素。

小组件按 WidgetKit 时间线请求新画面,大约每 15 分钟一次。具体时刻由 iOS 根据电量、使用情况与系统预算决定,所以请让画面在两次更新之间依然有意义。

不会。设备直接调用你的接口。你还可以设置密钥,让每个请求都带上 HMAC-SHA256 签名,供你的服务器验证。

点阵、文字、曲线、图片、图标、线条和形状,都是表达内容的元素,可以按需自由组合,并通过简单的路径绑定到你的数据。承载它们的卡片也有自己的风格:Liquid Glass、玻璃、纯色、渐变、氛围光或图片。

支持 iPhone 主屏幕的小、中、大尺寸小组件,以及待机显示。iPadOS、Apple Watch、灵动岛等已在规划中,上线后现有方案即可使用,无需额外付费。

有。我们提供 TypeScript、Python、Go、Java、C#、PHP、Ruby、Lua 和 C++ 九种语言的 SDK,帮你构造符合协议的 API 响应。你也可以不使用 SDK,自行实现 API、构造响应数据。

你的屏幕,由你定义。

把关心的事,放在眼前。