Manifest · 清单成员
share_target 清单成员
发布于
share_target 把已安装的 Web 应用注册为操作系统分享面板中的一个目标。用户选中该应用时,浏览器
把分享来的标题、文本、URL 与文件送到应用作用域内的一个 URL:要么作为 GET 导航的查询参数,要么
作为可被 Service Worker 拦截的 multipart/form-data POST。
Android 上的 Chrome 76、桌面端的 Edge 89(GET,文件支持有限)与 Samsung Internet 12.0 读取该
成员(BCD html.manifest.share_target)。iOS 与 macOS 上的 Safari 27 以及 Firefox 157 没有实现
它,应用不会出现在它们的分享面板里。该成员是分享的接收端;发送端是 navigator.share()。
- 类型:对象,含
action(接收分享的作用域内 URL)、method("GET"或"POST")、enctype("application/x-www-form-urlencoded"或"multipart/form-data")以及params: 一个把分享字段映射到参数名的对象,包括title、text、url,以及files,后者是{ "name", "accept" }数组,accept列出 MIME 类型或扩展名。 - 默认值:缺省,应用不是分享目标。对象内部
method默认"GET",enctype默认"application/x-www-form-urlencoded"。 - 示例值:
{ "action": "/share", "method": "GET", "params": { "title": "title", "text": "text", "url": "url" } }。
Chromium 校验这些组合,组合不合法时丢弃整个成员,并记入清单的错误列表:
invalid method. Allowed methods are: GET and POST.、
invalid enctype for GET method. Only application/x-www-form-urlencoded is supported.、
files are only supported with multipart/form-data POST.,以及 action 跨源或在 scope 之外时的
property 'share_target' ignored. Property 'action' is invalid.。因此文件要求 "method": "POST" 搭配
"enctype": "multipart/form-data";纯文本目标用默认值即可。
应用必须先安装才会出现在分享面板里,条目使用清单的 short_name 与图标。Android 把它与原生应用
并列显示;没有安装这个 PWA 的用户无法向它分享,所以分享目标页面还需要一条接收粘贴内容的普通
路由。分享载荷只有 text 没有 url 时,Android 上的 Chrome 经常把链接放在 text 里,处理器
要两个字段都解析。
示例沿着两条投递路径展开,最后处理两条路径都够不着的用户。
通过 GET 导航接收链接与文本
Section titled “通过 GET 导航接收链接与文本”一个稍后阅读应用接收三个文本字段。分享会在已安装应用中打开 /share?title=…&text=…&url=…,
页面在加载时读取查询串。由于 Android 有时把链接放在 text 里,处理器回退到在其中找到的第一个
URL。
{ "share_target": { "action": "/share", "method": "GET", "params": { "title": "title", "text": "text", "url": "url" } }}const params = new URLSearchParams(location.search);const text = params.get('text') ?? '';const url = params.get('url') ?? text.match(/https?:\/\/\S+/)?.[0] ?? null;
if (url) { saveLink({ title: params.get('title') ?? '', url });} else { showPasteForm(text); // 没有可分享的内容到达:让用户改为粘贴链接}保存后用 history.replaceState 清掉查询串,这样重新加载不会把同一个链接存两次。
通过 Service Worker 接收文件
Section titled “通过 Service Worker 接收文件”图片需要 POST 与 multipart 编码。Service Worker 拦截发往 action 的 POST,读取表单数据,保存
文件,然后用 303 重定向回应,让客户端落在一个普通的 GET 页面上;没有这次重定向,重新加载会
重复提交这次分享。
{ "share_target": { "action": "/share/upload", "method": "POST", "enctype": "multipart/form-data", "params": { "title": "title", "files": [{ "name": "photos", "accept": ["image/jpeg", "image/png", "image/webp"] }] } }}self.addEventListener('fetch', (event) => { const url = new URL(event.request.url); if (event.request.method !== 'POST' || url.pathname !== '/share/upload') return;
event.respondWith((async () => { const form = await event.request.formData(); const files = form.getAll('photos'); const cache = await caches.open('shared-inbox'); await Promise.all(files.map((file, i) => cache.put(`/shared/${Date.now()}-${i}`, new Response(file)))); return Response.redirect('/share/review', 303); })());});/share/review 页面列出 caches.open('shared-inbox') 里的内容,让用户确认后再上传到服务器,
这也覆盖了设备离线时到达的分享。
应用未安装时的回退
Section titled “应用未安装时的回退”分享面板只列出已安装的应用,Safari 27 与 Firefox 157 则根本不列出 Web 应用。一条接受粘贴内容、并在
navigator.share 存在时提供发送方向的路由,能让这项功能在任何地方都可用。
const canReceive = matchMedia('(display-mode: standalone)').matches; // 已安装:系统可以向我们分享const canSend = 'share' in navigator;
document.querySelector('#hint').textContent = canReceive ? '从任意应用分享并选择本应用。' : canSend ? '安装应用即可接收分享;现在仍可用按钮向外分享。' : '在输入框中粘贴链接或文本。';display-mode: standalone 只是“已安装”的代理信号,不保证分享目标已经注册;但它是页面能拿到的
最好信号。
- 接收分享内容(分享目标)
- Web Share API:浏览器调起原生分享面板
- scope 清单成员
- file_handlers 清单成员
- Web Share Target API(w3c.github.io)
- Receiving shared data with the Web Share Target API(developer.chrome.com)
规范
| 规范 | 状态 |
|---|---|
| Web Share Target API | W3C 草案 |