# Manifest widgets：操作系统小组件面板上的 PWA 内容

> manifest 的 widgets 字段如何为 PWA 声明操作系统小组件面板条目——tag、template/ms_ac_template、data、icons、screenshots 字段，service worker 的 widgetinstall 流程，以及目前在 Microsoft Edge/Windows 11 上的支持情况。

**一句话：** manifest 的 `widgets` 字段让已安装的 PWA 向操作系统的小组件面板注册一个或
多个小组件；随后由 service worker 响应小组件生命周期事件来渲染和更新每个小组件。

## 一个小组件条目声明了什么

`widgets` 是 manifest 上的一个 `WidgetDefinition` 对象数组。根据 PWA-driven Widgets
explainer 与微软的小组件操作指南，一个小组件定义对象的字段包括：

- **`name`** —— 展示给用户的小组件标题。
- **`description`** —— 描述该小组件的作用。
- **`tag`** —— 一个字符串，用于从 PWA 的 service worker 中引用该小组件，类似于
  `Notification` 的 tag。
- **`template`** —— 目前仅供参考，并不用于渲染该小组件。微软文档指出目前仅支持自定义
  的 **Adaptive Cards** 模板，通过必需的 **`ms_ac_template`** 字段提供，该字段给出该
  Adaptive Cards 模板的 URL。
- **`data`** —— 指向用于填充模板的 JSON 数据的 URL。
- **`icons`** —— 该小组件的备选图标数组；若未定义，则使用 manifest 的 `icons` 数组中
  所选的图标。
- **`screenshots`** —— 展示该小组件外观的 `ImageResource` 对象数组，与 manifest 的
  `screenshots` 字段类似。

## 从 service worker 渲染小组件

根据微软文档，安装 PWA 会把其 manifest 中的小组件添加到小组件面板，但一个小组件在
用户从该面板添加它之前不会被安装——也不会被渲染。service worker 必须监听
`widgetinstall` 事件，并调用 `self.widgets.updateByTag()`，使用该小组件的
`ms_ac_template` 与 `data` 来渲染它：

```js
self.addEventListener("widgetinstall", (event) => {
  event.waitUntil(renderWidget(event.widget));
});

async function renderWidget(widget) {
  const template = await fetch(widget.definition.msAcTemplate).then((r) => r.text());
  const data = await fetch(widget.definition.data).then((r) => r.text());
  await self.widgets.updateByTag(widget.definition.tag, { template, data });
}
```

## 浏览器与生态支持

| 引擎 | 支持情况 |
| --- | --- |
| Microsoft Edge（Windows 11） | 已实现，与 Windows 11 小组件面板集成，参见微软的 PWA 小组件操作指南 |

PWA-driven Widgets explainer 将其记录为一个提案与标准孵化的起点；微软的操作指南则
记录了已上线的 Edge/Windows 11 实现。由于这些来源未记录 Edge/Windows 11 之外的支持情况，
使用前请务必先做特性检测。

## 最小示例

```json
{
  "widgets": [
    {
      "name": "Task list",
      "description": "Your open tasks, at a glance",
      "tag": "task-list",
      "template": "task-list-template",
      "ms_ac_template": "widgets/task-list-template.json",
      "data": "widgets/task-list-data.json",
      "icons": [{ "src": "widgets/icon-96.png", "sizes": "96x96" }],
      "screenshots": [
        {
          "src": "widgets/screenshot-wide.png",
          "sizes": "600x400",
          "platform": "Windows",
          "label": "展示三个待办任务的任务列表小组件"
        }
      ]
    }
  ]
}
```

## 特性检测与回退

```js
// 位于 service worker 内（ServiceWorkerGlobalScope）。
self.addEventListener("widgetinstall", (event) => {
  if (!("widgets" in self)) {
    // 此处没有 widgets API——无需渲染。
    return;
  }
  event.waitUntil(renderWidget(event.widget));
});
```

## 实用清单

- [ ] 为每个小组件设置唯一的 `tag`——service worker 靠它来识别某次更新、
      `widgetinstall` 或其他生命周期事件属于哪个小组件。
- [ ] 提供 `name` 与 `description`——微软的小组件定义示例中，这两个字段与 `tag`、
      `template`、`data` 一样被填写。
- [ ] 不要依赖 `template` 来渲染小组件——目前仅支持通过 `ms_ac_template` 提供的
      自定义 Adaptive Cards 模板。
- [ ] 在 service worker 中监听 `widgetinstall` 并调用
      `self.widgets.updateByTag()`——加入 manifest 的小组件在 service worker 这样
      做之前不会被渲染。
- [ ] 若某个小组件省略了 `icons`，请确认 manifest 顶层的 `icons` 数组适合用作小组件
      面板的回退图标。
- [ ] 不要假设小组件能在 Microsoft Edge/Windows 11 之外渲染——这些来源仅记录了这一个
      已上线的实现。

## 延伸阅读

- [Manifest icons](/zh/reference/manifest/icons/) —— 小组件省略自身 `icons` 时使用的
  回退图标来源。
- [Manifest screenshots](/zh/reference/manifest/screenshots/) —— 与小组件的
  `screenshots` 共享形状的顶层字段。