接收分享的内容(share target)
发布于 更新于
一句话概括: 在 Web App Manifest 中声明 share_target,会将已安装的 PWA 注册到操作系统
原生的分享面板中,这样其他应用就可以直接把 URL、文本、标题和文件分享到你的应用,而不需要
你自己搭建一套单独的导入流程。
1. 在 manifest 中声明 share_target
Section titled “1. 在 manifest 中声明 share_target”根据 MDN 的说明,share_target 需要一个 action(接收分享内容的 URL)和 params
(分享字段到请求参数的映射);method 与 enctype 是可选的,默认分别为 "GET" 与
"application/x-www-form-urlencoded":
{ "share_target": { "action": "/share-handler", "method": "POST", "enctype": "multipart/form-data", "params": { "title": "title", "text": "text", "url": "url", "files": [ { "name": "media", "accept": ["image/*", "video/*"] } ] } }}默认的 GET 且不带 files 就足以接收纯文本/URL 分享;接收文件则必须显式设置
"method": "POST" 与 "enctype": "multipart/form-data",这一点来自 MDN 的说明。
2. 在 Service Worker 中处理请求
Section titled “2. 在 Service Worker 中处理请求”当操作系统在分享面板中提供了你的应用、且用户选择了它之后,浏览器会向 action 发送
一个 POST(或 GET)请求,其形式与表单提交完全一致。在 Service Worker 的 fetch
处理程序中拦截该请求并读取分享的数据。MDN 表示,POST 分享请求最好以 303 重定向响应,
以避免刷新时重复提交 POST;Chrome for Developers 也演示了这种模式:
self.addEventListener('fetch', (event) => { const url = new URL(event.request.url); if (event.request.method === 'POST' && url.pathname === '/share-handler') { 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-file-${i}`, new Response(file))) ); // 重定向(带上应用检测分享启动所需的标记)到一个会把缓存的文件读回来的页面。 return Response.redirect('/share-handler/view?shared=1', 303); })()); }});3. 在应用中读取分享的数据
Section titled “3. 在应用中读取分享的数据”被重定向到的页面会读取 Service Worker 存储的内容——也就是上面缓存的文件——并在导入前 展示给用户:
async function loadSharedFiles() { const cache = await caches.open('shared-content'); const keys = await cache.keys(); const files = await Promise.all( keys .filter((req) => req.url.includes('/shared-file-')) .map((req) => cache.match(req).then((res) => res.blob())) ); return files;}share_target 具体支持哪些浏览器、平台与版本,请参见下方的兼容性数据:
- 图例
- 支持
- 部分支持
- 需开启标志
- 不支持
- 未知
| 浏览器 / 平台 | 支持 | 版本 | 置信度 | 来源 | 备注 |
|---|---|---|---|---|---|
| Chrome (Android) | 支持 | 76 | 低 | 来源 | — |
| Edge (Desktop) | 支持 | 89 | 低 | 来源 | 1 |
| Samsung Internet | 支持 | 12.0 | 低 | 来源 | — |
| Firefox (Desktop) | 不支持 | — | 低 | 来源 | 2 |
| Safari (iOS) | 不支持 | — | 低 | 来源 | 3 |
| Safari (macOS) | 不支持 | — | 低 | 来源 | 4 |
检测重定向路径并提供回退
Section titled “检测重定向路径并提供回退”此示例自行在重定向中添加了 shared 查询参数。页面可以检测这条由应用定义的重定向路径,
并在未检测到时渲染正常视图:
function isSharedRedirect() { return new URLSearchParams(location.search).has('shared');}
async function loadSharedFiles() { if (!('caches' in window)) { // 当前上下文不支持 Cache Storage——没有可读回的内容。 return []; } const cache = await caches.open('shared-content'); const keys = await cache.keys(); return Promise.all( keys .filter((req) => req.url.includes('/shared-file-')) .map((req) => cache.match(req).then((res) => res.blob())) );}
if (isSharedRedirect()) { loadSharedFiles().then(renderSharedFiles);} else { // 不存在应用定义的重定向标记——渲染正常的初始视图。 renderDefaultView();}-
share_target只对已安装的 PWA 生效——未安装的普通标签页不会出现在操作系统 的分享面板中。 - 根据 MDN 的说明,接收文件需要
"method": "POST"与"enctype": "multipart/form-data"——仅支持 GET 的目标无法接收files。 - 处理 POST 后优先使用
303重定向;MDN 称这是避免刷新页面时重复提交 POST 的 理想做法。 - 为被重定向到的路由提供一个由应用定义的标记(例如查询参数),这样当它被直接打开时 可以回退到正常界面。
- 在读取分享的文件后清除或使其过期,避免重复分享导致陈旧数据不断累积。
- manifest share_target 参考 —— 完整的
share_target语法,包括 GET 与 POST 的参数映射方式。 - manifest: share_target 支持情况 —— 该 manifest 成员的按浏览器兼容性数据。