接收分享的内容(share target)
发布于 更新于
完成本指南后,你的已安装 PWA 会出现在操作系统的分享面板中,从别的应用分享过来的一张照片会以 File
的形式落到你的页面里,供预览与导入。Web App Manifest 中的 share_target 声明接收 URL;浏览器随后像
表单提交一样向它发起 GET 或 POST,剩下的就是你熟悉的请求处理。
你需要一个带 Service Worker 的可安装 PWA(见让它可安装);在所有平台上,
分享面板都只在用户安装之后才列出 Web 应用。每个 manifest 只允许一个 share_target,所以不同类型的分享
在落地页上分流,而不是声明多个。
1. 在 manifest 中声明 share_target
Section titled “1. 在 manifest 中声明 share_target”action(接收 URL,须在 manifest 的 scope 之内)与 params(分享字段到请求参数名的映射)是必需的。
method 默认为 GET,enctype 默认为 application/x-www-form-urlencoded。接收文件要求 POST 配合
multipart/form-data,并提供一个 files 数组,每一项写明字段名与接受的 MIME 类型或扩展名;两种写法都列上,
因为各操作系统匹配的方式不同。
{ "name": "Scrapbook", "start_url": "/", "display": "standalone", "share_target": { "action": "/share", "method": "POST", "enctype": "multipart/form-data", "params": { "title": "title", "text": "text", "url": "url", "files": [{ "name": "media", "accept": ["image/*", ".png", ".jpg", "video/*"] }] } }}纯文本目标可以保留 GET 默认值:浏览器以 ?title=…&text=…&url=… 打开 action,页面读取
new URL(location).searchParams。GET 更容易调试,但会把分享的文本泄露到历史记录与服务器日志里;
POST 把它放在请求体中,而且是接收文件的唯一方式。
2. 在 Service Worker 中处理 POST
Section titled “2. 在 Service Worker 中处理 POST”页面读不到 POST 请求体,所以由 Service Worker 在 fetch 中拦截请求、读取 formData()、保存文件,
然后以 303 See Other 重定向到展示它们的页面。重定向很重要:它阻止刷新页面时再次提交这次分享。
重定向目标带一个标记(?shared=1),页面据此知道要去缓存里找。
self.addEventListener('fetch', (event) => { const url = new URL(event.request.url); if (event.request.method !== 'POST' || url.pathname !== '/share') return;
event.respondWith( (async () => { const formData = await event.request.formData(); const files = formData.getAll('media'); const cache = await caches.open('shared-content'); await Promise.all(files.map((file, i) => cache.put(`/shared/${i}`, new Response(file)))); const text = formData.get('text') || formData.get('url') || ''; return Response.redirect(`/share/view?shared=1&text=${encodeURIComponent(text)}`, 303); })(), );});像对待任何表单提交一样校验收到的内容:别的应用会把内容放进意料之外的参数,而请求体来自你无法控制的软件。
3. 在页面中读取分享的文件
Section titled “3. 在页面中读取分享的文件”被重定向到的页面检查标记,把保存的响应读回为 Blob,展示出来供确认,然后删除它们,
以免第二次分享捡到第一次的文件。不带标记直接打开 /share/view 时渲染正常视图。
function isSharedLaunch() { return new URLSearchParams(location.search).has('shared');}
async function takeSharedFiles() { if (!('caches' in window)) return []; const cache = await caches.open('shared-content'); const requests = await cache.keys(); const files = await Promise.all(requests.map((request) => cache.match(request).then((r) => r.blob()))); await Promise.all(requests.map((request) => cache.delete(request))); return files;}
if (isSharedLaunch()) { takeSharedFiles().then(renderSharedFiles);} else { renderDefaultView();}4. 安装,然后分享到应用里
Section titled “4. 安装,然后分享到应用里”从浏览器的 Install(英文界面)入口安装 PWA,打开任意相册应用,选择 Share,在系统面板中选中你的
应用名。重定向落到 /share/view,预览图由缓存的文件渲染出来。再从浏览器分享一个 URL,就能看到 Android 上
text 回退的实际效果。会在分享面板中提供已安装 Web 应用的浏览器列在下表:
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Android) | 支持 | 76 | 低 | 来源 | — |
| Edge (Desktop) | 支持 | 89 | 低 | 来源 | 1 |
| Samsung Internet | 支持 | 12.0 | 低 | 来源 | — |
| Firefox (Desktop) | 不支持 | — | 低 | 来源 | 2 |
| Safari (iOS) | 不支持 | — | 低 | 来源 | 3 |
| Safari (macOS) | 不支持 | — | 低 | 来源 | 4 |
- Manifest share_target 字段
- Web Share API:从浏览器调起原生分享面板
- manifest: share_target 支持情况
- Receiving shared data with the Web Share Target API(developer.chrome.com)
- share_target(developer.mozilla.org)
← 返回指南总览。