本规范定义了一个 API,该 API 允许 Web 应用程序 针对已打开的应用实例,配置应用启动的行为。此 API 旨在满足 单实例 Web 应用的需求,例如音乐播放器。
为了实现此 API,用户代理必须支持 [[[appmanifest]]]。
一个音乐播放器应用希望将应用快捷方式启动指向一个既有 窗口,而不中断音乐播放。此音乐应用会向 [[[appmanifest]]] 添加一个 [=manifest/launch_handler=] 条目,如下所示:
{
"name": "Music Player",
"shortcuts": [{
"name": "Now Playing",
"url": "/"
}, {
"name": "Library",
"url": "/library"
}, {
"name": "Favorites",
"url": "/favorites"
}, {
"name": "Discover",
"url": "/discover"
}],
"launch_handler": {
"client_mode": "focus-existing"
}
}
[=manifest/client_mode=] 参数被设置为 [=client mode/focus-existing=],会使应用启动将 既有应用实例(如果有)置于焦点,而不会使其离开 当前文档进行导航。
一个 {{LaunchParams}} 将被加入 {{Window/launchQueue}} 队列, 音乐播放器可在其 {{LaunchConsumer}} 中读取 {{LaunchParams/targetURL}} 并在脚本中处理它,例如:
window.launchQueue.setConsumer((launchParams) => {
const url = launchParams.targetURL;
// 如果 URL 指向应用的某个区段,则将应用视图更新到
// 该区段,而不中断当前正在播放的音乐。
if (maybeFocusAppSection(url)) {
return;
}
// 无法就地处理该启动,只需导航页面
//(会中断任何正在播放的音乐)。
location.href = url;
});
一个已经在使用音乐播放器应用听音乐的用户, 激活 "Library" 应用快捷方式将触发到 /library 的应用启动,该启动会被路由到既有应用实例, 加入页面的 {{Window/launchQueue}} 队列,并通过已分配的 {{LaunchConsumer}} 将音乐播放器的资料库区段置于 焦点,而不影响当前的音乐播放。
以下步骤会被添加到 扩展点, 该扩展点位于 处理 清单的步骤中:
`launch_handler` 是一个 字典,包含关于 Web 应用启动应如何行为的配置。
尽管 [=manifest/client_mode=] 是唯一成员, [=manifest/launch_handler=] 仍然是一个字典。这是为了给 将来在需要其他类型的行为时添加更多成员预留空间。
处理 launch_handler 成员的步骤,在给定 [=ordered map=] |json:ordered map|、[=ordered map=] |manifest:ordered map| 时,如下:
[=manifest/launch_handler=] 的 `client_mode` 成员是一个 [=string=] 或 [=strings=] 列表,指定一个或多个 [=client mode targets=]。一个 [=client mode target=] 声明一种用于 Web 应用启动的特定客户端选择和导航行为。
用户代理可以仅支持 [=client mode targets=] 的一个子集, 具体取决于平台的约束(例如,移动设备可能不支持 多个应用实例同时存在)。
客户端模式目标如下:
用户代理预期会决定最适合该平台的行为。 例如,在只支持单个应用实例的移动设备上, 用户代理可以使用 `navigate-existing`; 而在支持多个窗口的桌面设备上,用户代理可以使用 `navigate-new` 以避免数据丢失。
页面必须在 {{Window/launchQueue}} 上设置 {{LaunchConsumer}},以接收该启动的 {{LaunchParams}} 并对其进行处理。如果页面未采取任何操作, 该启动的用户体验很可能看起来像是损坏的。
要处理 `client_mode` 成员,在给定 [=ordered map=] |json_launch_handler:ordered map|、[=ordered map=] |manifest_launch_handler:ordered map| 时,运行以下步骤:
`client_mode` 接受字符串列表,以允许站点指定在首选 [=client mode target=] 不受用户代理或平台支持时使用的 后备 [=client mode targets=]。列表中第一个受支持的 [=client mode target=] 条目会被使用。
本规范替换既有的 [=launch a web application=] 算法,以通过将其替换为 [=launch a web application with handling=] 的步骤来包含 [=manifest/launch_handler=] 的行为。
带处理地启动 Web 应用的步骤由以下 算法给出。该算法接受一个 [=Document/processed manifest=] |manifest:processed manifest|、一个可选的 [=URL=] 或 {{LaunchParams}} |params|、一个可选的 [=POST resource=] |POST resource|,并返回一个 [=application context=]。
|application context| 可能是一个已有实例,并具有 [=assigned launch consumer=],因此有必要处理 新追加的 {{LaunchParams}}。
准备应用上下文的步骤由以下算法给出。 该算法接受一个 [=Document/processed manifest=] |manifest:processed manifest|、一个 {{LaunchParams}} |launch params|、一个可选的 [=POST resource=] |POST resource|,并返回一个 [=application context=]。
对 |client mode| 进行切换,运行以下子步骤:
一种合适的选择策略是选取最近处于焦点的那个。
给定一个 {{LaunchQueue}} |queue| 时, 处理未消费的启动参数的步骤如下:
[Exposed=Window] interface LaunchParams {
readonly attribute DOMString? targetURL;
readonly attribute FrozenArray<FileSystemHandle> files;
};
{{LaunchParams/targetURL}} 表示该启动的 [=URL=],该 URL 必须是该应用的 [=manifest/within scope=]。
对于 {{LaunchParams/files}} 中的每个 |file handle:FileSystemHandle|, 使用设置为 {{FileSystemPermissionMode/"readwrite"}} 的 {{FileSystemPermissionDescriptor/mode}} 查询文件系统权限时, 必须返回 {{PermissionState/"granted"}}。
callback LaunchConsumer = any (LaunchParams params);
partial interface Window {
readonly attribute LaunchQueue launchQueue;
};
[Exposed=Window] interface LaunchQueue {
undefined setConsumer(LaunchConsumer consumer);
};
{{LaunchQueue}} 具有一个 未消费的启动参数, 它是 {{LaunchParams}} 的 [=list=],初始为空。
{{LaunchQueue}} 具有一个 已分配的启动消费者, 它是一个可选的 {{LaunchConsumer}},初始为 null。
{{LaunchQueue/setConsumer(consumer)}} 方法步骤为:
{{LaunchParams}} 通过 {{LaunchQueue}} 传递给文档, 而不是通过事件传递,以避免在启动事件触发与页面脚本 附加事件监听器之间出现竞态条件。相比之下, {{LaunchQueue}} 会缓冲所有已入队的 {{LaunchParams}}, 直到设置 {{LaunchConsumer}} 为止。
本规范没有已知的可访问性考虑。
对于 [=manifest/client_mode=] 为 [=client mode/focus-existing=] 的启动,实现者在 [=launching a web application with handling=] 时应当谨慎。这些启动不得泄露 [=manifest/navigation scope=] 之外的 URL。给定一个 [=Document/processed manifest=] |manifest| 时,这在两个方向上均适用: