Manifest · 清单成员
file_handlers 清单成员
发布于
file_handlers 是一个处理器对象数组。应用安装后,它把 PWA 注册为操作系统中所列 MIME 类型与
扩展名的打开程序:在 Finder、资源管理器或“文件”应用中打开匹配的文件,会以处理器的 action URL
启动应用,页面再通过 window.launchQueue 读取文件。清单成员只负责建立注册关系,文件本身仍要由
页面用 JavaScript 消费。
Chrome 102 与 Edge 102 在 Windows、macOS、Linux 与 ChromeOS 上处理该成员(BCD
html.manifest.file_handlers)。Android 版 Chrome、Safari 27、Firefox 157 与 Samsung Internet
会丢弃它,因此 PWA 的文件关联只存在于桌面 Chromium。
- 类型:对象数组。每个对象包含
action(字符串 URL)、accept(把 MIME 类型映射到扩展名 数组的对象)、可选的icons(操作系统为该类型文件显示的图像资源数组)以及可选的launch_type("single-client"或"multiple-clients")。 - 默认值:不注册。成员缺失,或用户在系统层面移除了关联时,打开文件不会启动应用。
- 示例值:
[{ "action": "/open", "accept": { "text/markdown": [".md"] } }]。
Chromium 逐个校验处理器。action 必须是清单 scope 内的 URL;越界或无法解析的 action 会让
该处理器被丢弃,解析器消息为 FileHandler ignored. Property 'action' is invalid.;accept 不是
“MIME 类型到扩展名数组”的对象时,消息为 FileHandler ignored. Property 'accept' is invalid.
(Chromium manifest_parser.cc)。扩展名必须以点开头;操作系统注册的是 MIME 类型键,所以
text/markdown 配 [".md", ".markdown"] 会同时认领两个后缀。
launch_type 默认为 "single-client":一次打开多个文件时,它们作为一个 LaunchParams 交给同一个
窗口,files 里有多个条目。设为 "multiple-clients" 时,每个文件各自启动一次,files 只含一个句柄。
Windows 不区分这两种设置,无论如何都按文件逐个启动应用(developer.chrome.com,“Handle files in
Progressive Web Apps”)。
首次通过处理器打开文件时,Chromium 会在页面拿到文件之前弹出权限对话框。授权按应用和文件类型记录;
清单更新改动了 file_handlers 时授权会被重置,用户也可以在该应用的网站设置里撤销。在 Windows 与
macOS 上,这个关联要和原生应用争夺同一扩展名,用户可能仍需从“打开方式”菜单中选择该 PWA。
下面两份清单注册了一个 Markdown 编辑器;脚本展示页面如何接收句柄,以及没有文件到达时怎么办。
为两个扩展名注册 Markdown 编辑器
Section titled “为两个扩展名注册 Markdown 编辑器”一个处理器同时认领 .md 与 .markdown,把每次启动都路由到 /editor,并提供一个操作系统可
显示在该类型文件上的图标。scope 显式写出,以确保 action URL 明确位于其内。
{ "name": "Draft", "start_url": "/", "scope": "/", "display": "standalone", "file_handlers": [ { "action": "/editor", "accept": { "text/markdown": [".md", ".markdown"], "text/plain": [".txt"] }, "icons": [{ "src": "/icons/markdown-file.png", "sizes": "256x256", "type": "image/png" }], "launch_type": "single-client" } ]}在 Chrome 102+ 上安装后,操作系统会把 Draft 列为 .md、.markdown 与 .txt 的打开程序。忽略
该成员的浏览器上什么都不会变:清单依旧有效,应用照常安装。
消费启动参数并回退到文件选择器
Section titled “消费启动参数并回退到文件选择器”/editor 页面应尽早设置 launchQueue 消费者:消费者设置之前到达的启动会被排队,但如果等到用户
操作之后再设置,就赶不上第一个文件了。launchQueue 不存在时(桌面 Chromium 之外的任何浏览器),
把同一个函数接到一个打开 <input type="file"> 的按钮上。
async function openHandle(handle) { const file = await handle.getFile(); editor.value = await file.text(); document.title = `${file.name} - Draft`;}
if ('launchQueue' in window) { window.launchQueue.setConsumer(async (launchParams) => { if (!launchParams.files.length) return; // 从图标启动,而不是从文件启动。 for (const handle of launchParams.files) await openHandle(handle); });} else { // 这里不可能发生文件处理启动,改为提供选择器。 openButton.hidden = false; openButton.addEventListener('click', () => picker.click()); picker.addEventListener('change', async () => { const [file] = picker.files; if (file) editor.value = await file.text(); });}launchParams.files 中是 FileSystemFileHandle 对象,同一个句柄之后可以传给 createWritable()
直接写回被打开的文件,无需保存对话框;<input type="file"> 回退得到的是普通 File 对象,无法写回。
从操作系统侧核对注册
Section titled “从操作系统侧核对注册”没有任何 JavaScript API 能报告系统关联是否存在。安装后到操作系统里核对:Windows 11(英文界面)
打开 Settings > Apps > Default apps,搜索扩展名,PWA 会以清单 name 出现;macOS 在 Finder 中
选中匹配文件,用 File > Get Info > Open with 查看。若应用不在列表里,去 DevTools > Application >
Manifest 看 Errors and warnings 里有没有关于该处理器的一行。
{ "file_handlers": [ { "action": "https://other.example/open", "accept": { "text/markdown": [".md"] } } ]}这个处理器被丢弃,因为 action 指向的源与清单 scope 不同;控制台显示
Manifest: FileHandler ignored. Property 'action' is invalid.,操作系统也永远不会得知这个类型。
- 处理文件
- File System Access API:读写本地文件
- launch_handler 清单成员
- scope 清单成员
- Manifest Incubations: file_handlers member(wicg.github.io)
- Let installed web applications be file handlers(developer.chrome.com)
- Handle files in Progressive Web Apps(learn.microsoft.com)
规范
| 规范 | 状态 |
|---|---|
| Web 应用清单:file_handlers | 参考文档 |
| Manifest Incubations: file_handlers member | WICG 草案 |
| Web App Launch Handler API | WICG 草案 |
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Desktop) | 支持 | 102 | 高 | 来源 | — |
| Chrome (Android) | 不支持 | — | 高 | 来源 | 1 |
| Edge (Desktop) | 支持 | 102 | 高 | 来源 | 2 |
| Firefox (Desktop) | 不支持 | — | 高 | 来源 | 3 |
| Firefox (Android) | 不支持 | — | 高 | 来源 | 45 |
| Safari (macOS) | 不支持 | — | 高 | 来源 | 6 |
| Safari (iOS) | 不支持 | — | 高 | 来源 | 78 |
| Samsung Internet | 不支持 | — | 高 | 来源 | 910 |
| WebView (Android) | 不支持 | — | 高 | 来源 | 1112 |
- browser-compat-data 未记录 Chrome Android 的支持。
- 由 browser-compat-data 镜像自 Chrome 的数据推导。
- browser-compat-data 未记录 Firefox 的支持。
- browser-compat-data 未记录 Firefox for Android 的支持。
- 由 browser-compat-data 镜像自 Firefox 的数据推导。
- browser-compat-data 未记录 Safari 的支持。
- browser-compat-data 未记录 iOS 版 Safari 的支持。
- 由 browser-compat-data 镜像自 Safari 的数据推导。
- browser-compat-data 未记录 Samsung Internet 的支持。
- 由 browser-compat-data 镜像自 Chrome Android 的数据推导。
- browser-compat-data 未记录 WebView Android 的支持。
- 由 browser-compat-data 镜像自 Chrome Android 的数据推导。
在线试用
在 OpenPWA 演示应用中运行此能力: /demo/#file-handling