# 插件图标与资源

## 插件图标

把图标图片放进插件包，在清单顶层的 `icon` 中填写相对于包根目录的路径：

```json
{
  "icon": "assets/icon.png"
}
```

```text
my-plugin/
├── manifest.json
├── index.js
└── assets/
    └── icon.png
```

支持 PNG、JPEG 和 WebP，单张最多 8 MiB。建议使用 512 × 512 的正方形图片；需要圆角或留白时，在 PNG 或 WebP 中保留透明背景。主程序会按容器等比显示图片。

路径使用 `/` 分隔，例如 `assets/icon.png`。文件必须在插件包中，不能填写绝对路径、网址或 `../`。打包、桌面安装和商店上传会检查这项声明。

插件列表、详情和流程编辑器“按插件”分类通过通用资源接口读取图片，不需要启动插件，也不需要额外权限。如果省略 `icon`，界面显示默认插件图标。插件安装后图片被移除或无法显示时，也会使用默认图标。


## 资源接口

主程序以插件 ID 和包内路径读取资源。HTTP 接口为：

```text
GET /api/extensions/{pluginId}/resources/{path}
```

例如，清单声明 `"icon": "assets/icon.png"` 后，可通过 `/api/extensions/example.clock/resources/assets/icon.png` 读取图片。接口只公开清单声明的展示资源，目前是顶层 `icon`，其他文件返回 `404`。小组件页面仍通过自己的[页面资源接口](../protocol/v1/page-bridge.md)加载 HTML、样式和脚本。

桌面渲染进程使用 `extensionAPI.getResource(pluginId, path)`，得到 `{ mimeType, dataUrl }`；读不到资源时返回 `null`。这属于主程序的界面接口，插件后台无需调用它。

## 动作、预设与分类图标

`actions[].icon`、`buttonPresets[].icon` 和 `categories[].icon` 支持引用统一图标库中的图标，或指定插件包内的 SVG 文件。图标库包含宿主内置图标包及已启用插件提供的图标包。

### 引用图标库

使用按钮编辑器“外观 → 自定义 → 图标包”中的图标 ID。宿主内置图标无需额外安装；插件图标包需要先安装并启用提供方。

```json
{
  "id": "open-site",
  "title": "打开网站",
  "icon": "host:outline/Globe"
}
```

内置 Ionicons 包为 `outline`（线性）、`filled`（实心）、`sharp`（锐角）和 `brand`（品牌），例如 `host:filled/Home`、`host:sharp/FingerPrint`、`host:brand/LogoGithub`；也可以选择内置彩绘包及插件图标包。名称区分大小写。插件图标使用 `plugin:<pluginId>/<packId>/<iconId>`，清单引用其他插件的图标时须声明对应依赖。

### 自定义 SVG

将文件放入插件包，在同一字段中写相对路径：

```json
{
  "id": "custom-tool",
  "title": "自定义工具",
  "icon": "assets/icons/tool.svg"
}
```

```svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  <path d="M4 12h16M12 4v16"/>
</svg>
```

使用 `currentColor` 跟随主题和选中状态，也可使用固定颜色。每个 SVG 最多 32 KiB，必须具有有效的 `viewBox`；支持 `svg`、`g`、`path`、`circle`、`ellipse`、`rect`、`line`、`polyline`、`polygon` 及常见绘图属性。导出时请将文字转为路径，移除内嵌样式、渐变和滤镜。

不支持脚本、事件属性、`style`、动画、外链、图片或嵌入 HTML。文件不能越出包目录或经过符号链接。桌面端加载和商店包检查均验证 SVG；显示时不执行插件代码。文件安装后丢失时回退为默认图标。

以上声明同时用于动作选择器、预设列表和流程编辑器分类。顶层 `icon` 仍是插件封面图片，使用 PNG、JPEG 或 WebP，与这些列表图标分开。

名称拼错、文件不可用或省略时，飞块显示默认图标。按钮本身的图标使用对象格式，例如 `{ "kind": "icon-pack", "id": "host:outline/Globe" }`，见 [ButtonIcon](./presets.md#buttonicon)。

## 超级块页面中的宿主图标

宿主支持 `widgets.icons: 1` 时，页面可调用 `await window.FlyonDeckWidget.getIcon('host:filled/Sunny')`，获取 `{ id, revision, paint, content }`；未知图标返回 `null`。此只读接口无需权限。`content.format` 为 `svg` 时，`content.svg` 保留 `currentColor`，可由页面 CSS 设置颜色和尺寸，也支持宿主解析后的包内 SVG data URI。接口不支持文件路径或外部 URL。

通用数值控件可从 `getControlValue()` 的可选 `icon` 字段获取目标动作图标，再交给 `getIcon()` 渲染。页面需要先通过 `onState()` 收到宿主快照。所有插件超级块共用此接口。

设置字段 `{ "type": "string", "title": "图标", "control": "icon", "default": "" }` 会显示宿主图标选择器；保存图标 ID，空字符串使用默认图标。

## IconPack

插件通过 `contributes.iconPacks` 提供静态图标包，要求 `hostCapabilities.required["icons.library"]: 1`。每个包声明 `id`、`title`、`paint` 和 `index`，可选 `titleKey`、`description`、`descriptionKey`、`license`。索引路径及其图标文件路径均相对于插件包根目录。

索引格式为 `{ "schemaVersion": 1, "icons": [{ "id": "play", "title": "播放", "file": "icons/play.svg", "keywords": ["play"] }] }`。索引条目可选 `titleKey`，从本插件词典翻译。宿主分配身份，索引不能指定其他资源所属插件。

图标 ID 统一为 `host:<packId>/<iconId>` 或 `plugin:<pluginId>/<packId>/<iconId>`。不接受旧的冒号图标 ID。动作、分类、预设、动态外观及 `control: "icon"` 设置使用同一身份协议；跨插件的清单引用须声明 dependencies。

`paint: "monochrome"` 只接受使用 currentColor 或 none 的静态 SVG；`paint: "original"` 接受固定颜色 SVG、PNG、WebP，不允许 currentColor 或动画。SVG 最多 32 KiB；图片最多 256 KiB、1024×1024；每包最多 4096 个图标、索引最多 1 MiB，每插件最多 8 包、8192 图标及 32 MiB 图标资源，同时服从归档总限制。

仅提供图标包的插件省略 main、permissions 为空，不声明其他贡献、插件依赖或原生运行时要求。资源不需要代码授权，不启动后台。后台停止或崩溃不影响已启用静态资源；整体禁用及卸载会移除目录。升级完整校验后原子替换，失败保留旧包。

桌面图标选择器通过统一目录分页搜索，页面 `getIcon(iconId)` 返回 `{id, revision, paint, content}` 或 null；content 为 `{format: "svg", svg}` 或 `{format: "png" | "webp", dataUrl, width, height}`。已保存按钮保留 PNG 快照及 iconRef、iconRevision；移除来源不删除快照。动态引用使用当前目录，缺失时采用显式配置的缺失处理。

完整示例见 [纯图标包示例](../guides/examples.md#静态图标包)，无需创建后台入口。

代码插件仅通过图标引用依赖另一代码插件、且没有声明该提供方的服务 uses 时，只要求资源已安装并启用，不启动或授权提供方后台。服务依赖仍按原有后台启动规则执行。
