将文件与 PWA 关联

在设备上,文件通常与应用相关联。因此,当用户打开文件时,操作系统会启动相应的应用并将文件传递给它。例如,HTML 文件通常在 Web 浏览器中打开,文本文件在文本编辑器中打开,视频在视频播放器中打开。

渐进式 Web 应用可以参与此功能,因此当用户单击特定类型的文件时,PWA 可能会被启动来处理它。

添加文件处理支持包括两个部分:

  • 使用 file_handlers web app manifest 成员声明对某些文件类型的支持。
  • 使用 LaunchQueue 接口处理文件。

注意:目前此功能仅适用于基于 Chromium 的浏览器,并且仅适用于桌面操作系统。

声明对文件类型的支持

要声明对特定文件类型的支持,请在 manifest 文件中包含 file_handlers 成员。

file_handlers 成员是一个文件处理程序对象的数组。每个文件处理程序对象都有两个必需属性:actionaccept

  • accept 属性包含处理程序知道如何处理的文件的 MIME 类型和相关文件扩展名。
  • action 属性是一个 URL,当用户打开文件时,PWA 将导航到该 URL。此页面必须在 PWA 的范围内。

下面的 manifest 文件包含一个带有单个处理程序的 file_handlers 成员,该处理程序可以处理 JPEGPNG 文件,并且当用户单击其中一个文件时,它将导航到 PWA 的根页面。

json
{
  "name": "File handling demo",
  "icons": [
    {
      "src": "icons/lightbulb.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "start_url": "/",
  "display": "standalone",
  "file_handlers": [
    {
      "action": "/",
      "accept": {
        "image/jpeg": [".jpg", ".jpeg"],
        "image/png": [".png"]
      }
    }
  ]
}

使用此 manifest,一旦安装了 PWA,当用户打开这些类型的文件时,它可能会被打开。

通常不止一个应用可以打开任何给定类型的文件,因此操作系统通常提供一项功能,允许用户选择使用哪个应用打开文件,并设置默认处理程序。例如,在 macOS 上,用户可以右键单击文件,选择“获取信息”,并在生成的对话框中配置默认处理程序

Selecting the default handler on macOS

请求权限

当浏览器首次将启动您的 PWA 来处理用户打开的一个或多个文件时,它会要求用户确认他们是否要使用您的 PWA 打开它。例如,Chrome 对话框如下所示

Chrome warning dialog for launching PWA to handle a file

处理文件

当浏览器启动您的 PWA 并导航到您在 file_handlers manifest 成员的 action 属性中指定的页面时,您需要运行一些代码来处理文件。此代码将在 action 属性中指定的页面中运行。

这里的关键接口是 LaunchQueue,它作为全局 Window 对象的属性提供。

LaunchQueue 接口有一个方法,setConsumer(),它接受一个回调函数作为参数,当浏览器启动 PWA 并带有一个或多个要处理的文件时,该回调函数将被调用。

回调函数会传递一个 LaunchParams 对象,该对象包含一个 files 属性,其中包含一个 FileSystemHandle 对象的数组,每个对象代表用户打开的一个文件。

例如,下面的代码读取文件并将其内容分配给 <img> 元素,然后将其添加到页面中

js
const imageContainer = document.querySelector("#container");

if ("launchQueue" in window) {
  launchQueue.setConsumer(async (launchParams) => {
    for (const file of launchParams.files) {
      const img = document.createElement("img");
      img.src = URL.createObjectURL(await file.getFile());
      imageContainer.appendChild(img);
    }
  });
}

请注意,代码在使用 launchQueue 之前会检查它是否存在,以确保应用在不支持该 API 的浏览器中也能正常运行。

另见