处理文件
发布于
完成本指南后,桌面用户双击一个 .csv 文件,或在 “Open with” 里选中你的应用,就会进入已安装的 PWA 并且文件已经加载;Android、Firefox 或 Safari 上的用户则通过应用内文件选择器完成同样的导入。系统级关联来自 file_handlers manifest 成员,在 PWA 安装时读取;读取文件则在页面 JavaScript 中通过 window.launchQueue 完成。
你需要一个可安装的 PWA(见入门)、Windows、macOS、Linux 或 ChromeOS 上的 Chrome 或 Edge 102 及以上,以及一种要接管的文件类型。
在 manifest 中声明处理程序
Section titled “在 manifest 中声明处理程序”file_handlers 的每一项都需要一个位于应用导航作用域内的 action URL,以及一个从 MIME 类型映射到扩展名的 accept 对象(MDN 把两者都标为必填)。Chrome 还读取可选的 icons 数组(让系统显示文件类型图标而不是应用图标)和 launch_type:
{ "file_handlers": [ { "action": "/open", "accept": { "text/csv": [".csv"] }, "icons": [ { "src": "/icons/csv-file.png", "sizes": "256x256", "type": "image/png" } ], "launch_type": "single-client" } ]}launch_type 默认为 "single-client":同时打开多个匹配文件只产生一次启动,LaunchParams.files 包含全部文件。改为 "multiple-clients" 时,Chrome 为每个文件各启动应用一次,每次启动的 files 数组只有一个元素。修改该成员后请重新安装 PWA;系统关联在安装时写入,而且 Chrome 会在 file_handlers 变化时重置文件处理权限。
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| 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 的数据推导。
Chrome 的能力文章写明文件处理 “limited to desktop operating systems”,所以即使 Android 接受这份 manifest,处理程序在那里也不起作用。
在页面中消费启动
Section titled “在页面中消费启动”当系统用该应用打开文件时,Chrome 导航到 action 并把一个 LaunchParams 对象放入 window.launchQueue;Chrome 的 launch-handler 文档把该队列描述为保留启动 “until they are handled by the specified consumer”,所以页面启动完成后才注册的 consumer 仍能收到启动。在顶层注册一次,不要放在任何异步启动逻辑之后:
window.launchQueue.setConsumer(async (launchParams) => { if (!launchParams.files || launchParams.files.length === 0) return; for (const handle of launchParams.files) { const file = await handle.getFile(); renderCsv(file.name, await file.text()); }});files 中的每一项是文件句柄而不是 File,所以 consumer 在读取前要先调用 getFile()。
检测支持并回退到选择器
Section titled “检测支持并回退到选择器”Chrome 的文章给出的检测是 'launchQueue' in window && 'files' in LaunchParams.prototype;后半句很重要,因为浏览器可能为 launch_handler 导航提供了 launchQueue,却没有 files 成员。检测失败时显示标准的文件输入框,让功能仍然存在,只是没有系统集成:
function supportsFileHandling() { return 'launchQueue' in window && 'files' in LaunchParams.prototype;}
const picker = document.querySelector('#open-file-input'); // <input type="file" accept=".csv">
if (supportsFileHandling()) { window.launchQueue.setConsumer(async (launchParams) => { for (const handle of launchParams.files ?? []) { const file = await handle.getFile(); renderCsv(file.name, await file.text()); } });} else { picker.hidden = false; picker.addEventListener('change', async () => { const [file] = picker.files; if (file) renderCsv(file.name, await file.text()); });}桌面上也要保留选择器入口:没有安装应用的用户,或先打开应用再想找文件的用户,都没有系统启动可依赖。
安装 PWA,然后从系统文件管理器打开一个 .csv。首次启动时,应用读取文件前会出现 Chrome 的权限提示;允许后 consumer 运行,files 中有一项。
file_handlersmanifest 成员file_handlers兼容性- 接收分享的内容(share target)
- File System Access
- Let installed web applications be file handlers(developer.chrome.com)
file_handlers(developer.mozilla.org)