能力 · API
Web Share API
发布于
navigator.share() 把 URL、标题、文本或文件交给操作系统的分享面板,PWA 不必自建分享菜单就能把内容发给用户装的任意应用。navigator.canShare() 同步校验同一份载荷,并且与 share() 不同,它不要求用户手势。
桌面端支持是局部的:Chrome 89 与 Edge 81 只在 Windows 和 ChromeOS 上实现(Chromium bug 40542648 与 40729163 跟踪 macOS 和 Linux),Firefox 71 把它放在 dom.webshare.enabled 偏好设置之后,Android WebView 没有实现(crbug.com/40540400)。macOS 上的 Safari 12.1、iOS 上的 Safari 12.2、Android 上的 Chrome 61 与 Firefox 79 均无附加条件地支持。
navigator.share()navigator.share(data)
navigator.canShare()navigator.canShare(data)share() 返回 Promise<undefined>,数据传给所选目标(或目标无法确认接收时传给操作系统)后兑现。canShare() 返回 boolean,是两者中唯一可以在用户激活处理函数之外调用的方法。两者都带 [SecureContext]:在 localhost 以外的 http:// 源上,navigator.share 为 undefined。
两个方法都接受一个可选的 data 参数,类型为 ShareData 字典。每个成员单独看都是可选的,但字典必须至少含有 title、text、url 之一或非空的 files,否则校验失败。
| 成员 | 类型 | 必填 | 说明 |
|---|---|---|---|
title |
USVString |
否 | 分享内容的标题。邮件类目标用作主题;许多即时通讯类目标会丢弃它。 |
text |
USVString |
否 | 自由文本正文,可与 url 同传或替代 url。 |
url |
USVString |
否 | 绝对或相对 URL,分享前按文档的 base URL 解析;"" 表示当前页面。只有 http:、https: 以及浏览器安全名单内的协议可分享。 |
files |
sequence<File> |
否 | 要分享的文件。没有其他成员时 { files: [] } 按空字典处理;{ text: "x", files: [] } 会被接受,空列表被忽略。 |
浏览器不认识的成员会被静默丢弃(WebIDL 字典语义),所以只认 title、text、url 的浏览器会分享这三项并忽略 files。需要确认每个成员都受支持时,把它们逐个单独传给 canShare()。
share() 以下列 DOMException 名称之一拒绝其 Promise,顺序即规范算法的检查顺序。
| 异常 | 条件 |
|---|---|
InvalidStateError |
文档不是 fully active,或上一次 share() 的 Promise 仍未完结([[sharePromise]] 非 null)。Chromium 在 Android 上跳过第二项检查。 |
NotAllowedError |
web-share Permissions Policy 拒绝了该文档(默认允许列表为 'self',跨源 iframe 需要 allow="web-share");或调用时没有瞬时用户激活;或某文件类型因安全原因被拦。 |
TypeError |
「validate share data」返回 false:没有任何成员;url 解析失败;url 使用 local scheme、file:、javascript:、ws:、wss: 或任何不可分享的协议;传了 files 但浏览器不支持文件分享,或判定某个文件可能有害。 |
AbortError |
没有可用的分享目标,或用户关闭了分享面板。 |
DataError |
所选目标启动失败,或向它传输数据失败。 |
canShare() 不抛任何异常。它对会让 share() 以 TypeError 拒绝的那些条件返回 false,其余情况返回 true,包括 share() 之后会因用户取消而以 AbortError 拒绝的情况(见 canShare() 算法(w3.org))。
每个示例都先做特性检测,并给出不支持时实际执行的分支。三段代码都必须由 click 之类的用户激活处理函数触发。
分享当前页面,缺少支持时回退到剪贴板
Section titled “分享当前页面,缺少支持时回退到剪贴板”绑定按钮前先检测 navigator.share;缺失时(偏好设置关闭的桌面 Firefox、Android WebView、任何 http:// 源)改为复制 URL 并告知用户。分享调用本身必须留在 click 处理函数内,这样 share() 执行时瞬时激活仍然有效。
const button = document.querySelector('#share');
button.addEventListener('click', async () => { const payload = { title: document.title, url: location.href };
if (!navigator.share) { await navigator.clipboard.writeText(location.href); button.textContent = '链接已复制'; return; }
try { await navigator.share(payload); } catch (err) { if (err.name === 'AbortError') return; // 用户关闭了面板 console.error(`${err.name}: ${err.message}`); }});在 share() 之前 await 任何东西(统计上报、一次 fetch)是丢失激活的常见原因;先分享,待 Promise 兑现后再记录事件。
仅在 canShare() 接受时分享生成的文本文件
Section titled “仅在 canShare() 接受时分享生成的文本文件”文件分享的支持面比 URL 分享窄:Android 上的 Chrome 76 加入,桌面 Chrome 89 只在 Windows 和 ChromeOS 上分享文件,Safari 14 加入 files,Firefox 任何版本都没有文件分享(BCD api.Navigator.share.data_files_parameter)。先构造 File,用 canShare() 询问当前浏览器是否接受,不接受时回退为下载链接。
async function shareReport(csvText) { const file = new File([csvText], 'report.csv', { type: 'text/csv' });
if (navigator.canShare?.({ files: [file] })) { try { await navigator.share({ files: [file], title: '报表' }); } catch (err) { if (err.name !== 'AbortError') throw err; } return; }
const link = document.createElement('a'); link.href = URL.createObjectURL(file); link.download = file.name; link.click(); URL.revokeObjectURL(link.href);}浏览器完全不能分享文件,或只是拒绝这一个文件,canShare({ files }) 都返回 false,所以一个回退分支就能覆盖两种情况。
多成员分享前逐个检查成员
Section titled “多成员分享前逐个检查成员”未知成员被忽略而不是被拒绝,所以不支持 files 的浏览器仍会兑现 share({ text, files }),只是只分享了文本。部分分享会误导用户时,按成员逐个校验。
function supportedMembers(data) { if (!navigator.canShare) return []; return Object.entries(data) .filter(([key, value]) => navigator.canShare({ [key]: value })) .map(([key]) => key);}
const data = { title: '旅行照片', text: '周末拍的', files: photoFiles };const ok = supportedMembers(data);
if (ok.includes('files')) { await navigator.share(data);} else { await navigator.share({ title: data.title, text: data.text, url: galleryUrl });}设备带不动文件本身时,url 分支让接收方拿到指向同一批照片的链接。
- Manifest share_target 字段,分享的接收端
- 接收分享的内容(share target)
- Async Clipboard API,
navigator.share为 undefined 时的常用回退 - Web Share API: share() method(w3.org)
- Web Share API: validate share data(w3.org)
- Chromium bug 40542648: Web Share on macOS(crbug.com)
- Chromium bug 40540400: Web Share in Android WebView(crbug.com)
规范
| 规范 | 状态 |
|---|---|
| Web Share API(网页分享) | W3C |
| Web Share API: share() method | W3C |
| Web Share API: canShare() method | W3C |
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Desktop) | 部分支持 | 89 → 128 | 高 | 来源 | 1 |
| Chrome (Android) | 支持 | 61 | 高 | 来源 | — |
| Edge (Desktop) | 部分支持 | 81 → 93 | 高 | 来源 | 2 |
| Firefox (Desktop) | 需开启标志 | 71 | 高 | 来源 | 3 |
| Firefox (Android) | 支持 | 79 | 高 | 来源 | — |
| Safari (macOS) | 支持 | 12.1 | 高 | 来源 | — |
| Safari (iOS) | 支持 | 12.2 | 高 | 来源 | 4 |
| Samsung Internet | 支持 | 8.0 | 高 | 来源 | 5 |
| WebView (Android) | 不支持 | — | 高 | 来源 | 6 |
在线试用
在 OpenPWA 演示应用中运行此能力: /demo/#share