跳转到内容

Manifest · 清单成员

launch_handler 清单成员

发布于

有限可用不支持的浏览器: Firefox (Desktop)、Firefox (Android)、Safari (macOS)、Safari (iOS)WICG 草案

launch_handler 告诉浏览器:已安装的 Web 应用再次被启动时(来自系统启动器、快捷方式、文件关联、 协议链接或分享),该怎样处理它已经打开的窗口。它唯一的属性 client_mode 在三种做法之间选择: 聚焦已打开的窗口、让该窗口导航到启动 URL,或新开一个窗口。

Chrome 110、Edge 110、Samsung Internet 21.0 与 Android WebView 110 实现了该成员(BCD html.manifest.launch_handler)。Firefox 157 与 Safari 27 解析后丢弃,所以在那里每次启动都会 新开窗口或标签页。启动 URL 通过 window.launchQueue 送达页面,focus-existing 正是靠它才有用。

  • 类型:对象,只有一个属性 client_mode,取字符串或字符串数组。允许的值:auto、 navigate-new、navigate-existing、focus-existing。
  • 默认值:auto。成员缺省、client_mode 不是字符串或数组、数组里没有任何可识别的值, 这三种情况都解析为 auto。
  • 示例值:{ "client_mode": ["focus-existing", "auto"] }。

已有窗口打开时,各模式的行为:

  • auto 把选择权交给浏览器。Chromium 在 Android 上取 navigate-existing(单实例是常态), 在桌面端取 navigate-new。
  • navigate-new 在启动 URL 处新开一个应用窗口。
  • navigate-existing 把最近使用的窗口提到前台,并让它导航到启动 URL。
  • focus-existing 把该窗口提到前台但不导航。页面通过 launchQueue 收到启动 URL,自行决定 怎么处理。

没有窗口打开时,focus-existing 与 navigate-existing 的表现等同于 navigate-new。对于数组, 浏览器取第一个它认得的值,因此清单可以优先 focus-existing,同时为将来新增模式的引擎写上 auto。

Chromium 解析器对形状很严格:非对象的值产生 launch_handler value ignored, object expected., client_mode 中未知的字符串产生 client_mode value '<value>' ignored, unknown value. (manifest_parser.cc 的 ParseLaunchHandler)。被跳过的只是无效条目,不是整个成员。

清单一侧只有一行;有意思的代码在 launchQueue 消费者里,是它让 focus-existing 真正做事。

保持单一编辑器窗口并把启动导入其中

Section titled “保持单一编辑器窗口并把启动导入其中”

一个文档编辑器只想要一个窗口,每次启动切换到被请求的文档,而不是堆叠窗口。清单请求 focus-existing;页面消费启动 URL 并更新自身状态。

{
"name": "Draft",
"start_url": "/",
"display": "standalone",
"launch_handler": { "client_mode": ["focus-existing", "auto"] },
"file_handlers": [
{ "action": "/open", "accept": { "text/markdown": [".md"] } }
]
}
if ('launchQueue' in window) {
window.launchQueue.setConsumer(async (launchParams) => {
const url = new URL(launchParams.targetURL);
if (launchParams.files.length > 0) {
const file = await launchParams.files[0].getFile();
await openDocument(file);
return;
}
const doc = url.searchParams.get('doc');
if (doc) await openDocumentById(doc);
});
} else {
// 没有 launchQueue:浏览器做的是普通导航,直接读 URL 即可。
const doc = new URL(location.href).searchParams.get('doc');
if (doc) await openDocumentById(doc);
}

消费者会为创建该窗口的那次启动运行一次,之后每一次被导入该窗口的启动再运行一次。启动来自文件 关联时,launchParams.files 是 FileSystemFileHandle 数组,否则为空。

launchQueue 是整套机制的检测点。没有它的浏览器会把每次启动都变成到 targetURL 的普通导航, 所以回退就是读 location。下面的辅助函数让应用其余部分无论哪种情况都只面对一个回调。

export function onLaunch(handler) {
if ('launchQueue' in window) {
window.launchQueue.setConsumer((params) => handler(new URL(params.targetURL)));
} else {
handler(new URL(location.href));
}
}
onLaunch((url) => {
if (url.pathname === '/share') showShareSheet(url.searchParams);
});

在模块的第一个 await 之前注册消费者:Chromium 会把启动参数排队到有消费者为止,晚注册的 消费者仍会被触发,所以不会丢,只会延迟。

桌面端偏好新窗口、移动端偏好现有窗口

Section titled “桌面端偏好新窗口、移动端偏好现有窗口”

一个新闻阅读器希望桌面端每次启动都在自己的窗口里,而在手机上只保留一个窗口。auto 在 Chromium 里已经编码了这种区分,清单把它显式写出来,把选择交给浏览器。

{
"launch_handler": { "client_mode": "auto" }
}

写出 auto 与省略该成员等价;这个值存在的意义是让日后修改清单时有一个明显的位置可改。

规范

规范状态
Web 应用清单:launch_handlerWICG 草案
  • 图例
  • 支持
  • 部分支持
  • 需开启标志
  • 不支持
  • 未知
浏览器 / 平台支持版本置信度来源备注
Chrome (Desktop)支持110高来源—
Chrome (Android)支持110高来源1
Edge (Desktop)支持110高来源2
Firefox (Desktop)不支持—高来源3
Firefox (Android)不支持—高来源45
Safari (macOS)不支持—高来源6
Safari (iOS)不支持—高来源78
Samsung Internet支持21.0高来源9
WebView (Android)支持110高来源10
  1. 由 browser-compat-data 镜像自 Chrome 的数据推导。
  2. 由 browser-compat-data 镜像自 Chrome 的数据推导。
  3. browser-compat-data 未记录 Firefox 的支持。
  4. browser-compat-data 未记录 Firefox for Android 的支持。
  5. 由 browser-compat-data 镜像自 Firefox 的数据推导。
  6. browser-compat-data 未记录 Safari 的支持。
  7. browser-compat-data 未记录 iOS 版 Safari 的支持。
  8. 由 browser-compat-data 镜像自 Safari 的数据推导。
  9. 由 browser-compat-data 镜像自 Chrome Android 的数据推导。
  10. 由 browser-compat-data 镜像自 Chrome Android 的数据推导。

源数据: /compatibility/manifest-launch-handler.json · 全球使用占比: 72 % (StatCounter 2026-05)

来源: 规范 · MDN · 最近核验 2026-10-03 · 置信度: 高 (由来源计算)