网页共享 API

W3C 推荐

更多关于本文档的详细信息
此版本:
https://www.w3.org/TR/2023/REC-web-share-20230530/
最新发布版本:
https://www.w3.org/TR/web-share/
最新编辑草案:
https://w3c.github.io/web-share/
历史记录:
https://www.w3.org/standards/history/web-share
提交历史
测试套件:
https://wpt.live/web-share/
实现报告:
https://w3c.github.io/web-share/imp-report/
编辑:
Matt Giuca (Google Inc.)
Eric Willigers (Google Inc.)
Marcos Cáceres (Apple Inc.)
反馈:
GitHub w3c/web-share (拉取请求, 新问题, 开放问题)
勘误:
存在勘误
浏览器支持:
caniuse.com

另见 翻译.


摘要

本规范定义了一个用于将文本、链接和其他内容共享到用户选择的任意目标的 API。

这里没有指定可用的共享目标;它们由用户代理提供。例如,它们可能是应用程序、网站或联系人。

本文档的状态

本节描述了本文档在发布时的状态。当前的 W3C 出版物列表和该技术报告的最新修订版可在 W3C 技术报告索引中找到,网址为 https://www.w3.org/TR/。

本文档由 Web 应用工作组 作为推荐标准发布,使用 推荐标准轨道

W3C 推荐广泛部署此规范作为 Web 标准。

W3C 推荐标准是一种规范,经过广泛的共识建立后,得到了 W3C 及其成员的认可,并且工作组成员承诺 免版税许可 以便实施。未来对此推荐标准的更新可能会包含 新功能

本文档由依据 W3C 专利政策运营的小组生成。 W3C 维护了一个 公开的专利披露列表 ,与该小组的可交付成果相关;该页面还包括 披露专利的说明。任何个人若已实际了解包含 必要声明的专利,必须根据 W3C 专利政策第 6 节披露信息。

本文档受 2021 年 11 月 2 日 W3C 过程文档的约束。

实施状态

本节是非规范性的。

内容共享功能通常依赖于底层操作系统提供的“共享”功能以及操作系统的用户界面约定。例如,某些操作系统呈现“共享面板”,而其他操作系统依赖于弹出菜单。由于上述依赖性,实施者正在继续努力将 Web 共享 API 带到所有操作系统。这项正在进行的工作反映在 实施报告中的失败情况,该报告是通过在有限的一组操作系统上运行测试生成的。然而,工作组对 Web 共享 API 能够随着时间的推移在所有操作系统上变得更加普遍感到乐观,并且它已经广泛应用于各种设备上的流行操作系统中。

1. 使用示例

本节为非规范性内容。

1.2 共享文件

此示例展示了如何共享文件。请注意,files 成员是一个数组,允许共享多个文件。

示例 2:共享文件
shareButton.addEventListener("click", async () => {
      const file = new File(data, "some.png", { type: "image/png" });
      try {
        await navigator.share({
          title: "Example File",
          files: [file]
        });
      } catch (err) {
        console.error("Share failed:", err.message);
      }
    });

1.3 验证共享

调用 canShare() 方法,并传入 ShareData 字典,来 验证共享数据。与 share() 不同,它可以在没有 瞬态激活的情况下调用。

const file = new File([], "some.png", { type: "image/png" });

    // 检查文件是否受支持
    if (navigates.canShare({files: [file]})) {
    // 共享一个png文件应该是可以的...
    }

    // 检查URL是否可以共享...
    if (navigates.canShare({ url: someURL })) {
    // URL有效,可能可以共享...
    }

1.4 检查是否支持成员

由于 WebIDL 字典的工作方式,传递给 share() 的未知成员会被用户代理忽略。 这可能会在共享多个成员时造成问题,但用户代理不支持其中的某个成员。为了确保传递的每个成员都受用户代理支持, 可以将它们单独传递给 canShare() 方法,以检查它们是否受支持。

示例 4:确保未来的共享兼容性
const data = {
  title: "示例页面",
  url: "https://example.com",
  text: "这是共享的文本",
  someFutureThing: "某个未来的东西",
};
const allSupported = Object.entries(data).every(([key, value]) => {
  return navigator.canShare({ [key]: value });
});
if (allSupported) {
  await navigator.share(data);
}

或者,您可以调整应用程序的 UI 以隐藏不支持的成员组件。

示例 5:过滤掉不支持的成员
const data = {
  title: "示例页面",
  url: "https://example.com",
  text: "这是共享的文本",
  someFutureThing: "某个未来的东西",
};

// 不支持的成员...
const unsupported = Object.entries(data).filter(([key, value]) => {
  return !navigator.canShare({ [key]: value });
});

1.5 在第三方上下文中启用 API

默认允许列表中的 'self' 使 Web Share API 默认仅在第一方上下文中可用。

第三方可以通过 iframeallow 属性启用该 API:

或者,可以通过指定 HTTP 响应头在第一方上下文中禁用该 API:

参见 权限策略 规范,了解更多详细信息以及如何根据每个来源控制权限策略。

2. API 定义

2.1 Navigator 接口的扩展

WebIDLpartial interface Navigator {
      [SecureContext] Promise<undefined> share(optional ShareData data = {});
      [SecureContext] boolean canShare(optional ShareData data = {});
    };

2.1.1 内部槽

该 API 向 Navigator 接口添加了以下内部槽。

Promise? [[sharePromise]]
this.[[sharePromise]] 是一个表示用户当前意图与 共享目标共享数据的承诺。它被初始化为 null

2.1.2 share() 方法

share() 方法被传入 data 参数调用时,执行下列步骤,并考虑以下安全问题。

Web Share 允许网站将数据发送到 共享目标,共享目标可以是本地应用程序。 虽然这种功能并不是 Web Share 独有的,但它确实伴随着一些潜在的安全风险,这些风险的严重程度会根据底层平台的不同而有所变化。

传递给 share() 的数据可能会被用来利用 共享目标中的缓冲区溢出或其他远程代码执行漏洞,接收共享内容时存在风险。虽然无法通用防护此类风险, 但实现者需要意识到这种可能性(特别是共享文件时)。

共享目标可能会取消引用共享的 URL 并转发该信息, 这可能会意外地转发本应保密的信息。如果共享的内容是仅对该应用程序、主机或其网络位置可访问的内容,这可能会导致意外的信息泄露。

恶意站点可能会通过提供最终解析为本地资源的 URL(如 "file:" URL 或本地服务)来利用信息泄露的共享目标, 这些资源可能是其他方式无法访问的。尽管该 API 将共享的 URL 限制在一组受限的 可共享方案内,但使用重定向或 DNS 记录的修改可能会导致应用程序获取内容。

为避免被用于这些攻击,共享目标可以处理 URL,并在不共享信息的情况下检索并处理内容。例如,照片编辑应用程序可能会检索共享的图像。 共享目标也可以仅共享 URL,而不获取任何引用的内容。

为预览或共享内容而获取内容的共享目标存在信息泄露的风险。预览并经用户授权的内容可能是安全的,但用户不一定总能识别出哪些信息应保密, 因此转发任何内容都存在风险。特别是,攻击者可能会利用 title 来诱骗用户误解内容的性质(另见 5. 可访问性注意事项)。

与使用 DOMException 一样, 实现者需要仔细考虑在 share() 被拒绝时错误消息泄露了哪些信息。 即便只是区分没有可用的 共享目标与用户取消操作的情况,也可能会透露有关用户设备上安装了哪些共享目标的信息。

  1. globalthis相关全局对象
  2. documentglobal关联的 Document
  3. 如果 document完全活动, 则返回 一个被拒绝的承诺, 错误类型为 InvalidStateError DOMException
  4. 如果 document 无法 使用 "web-share", 则返回 一个被拒绝的承诺, 错误类型为 NotAllowedError DOMException
  5. 如果 this.[[sharePromise]] 不为 null, 则返回 一个被拒绝的承诺, 错误类型为 InvalidStateError DOMException
  6. 如果 global 没有 瞬态激活, 则返回 一个被拒绝的承诺, 错误类型为 NotAllowedError DOMException
  7. 消耗 global 的用户激活。
  8. basethis相关设置对象API 基础 URL
  9. 如果使用 database 进行 共享数据验证 返回 false, 则返回 一个被拒绝的承诺, 错误类型为 TypeError
  10. 如果 dataurl 成员存在:
    1. url 设为对 dataurl 进行 URL 解析器 的结果, 使用 base
    2. 断言urlURL
    3. data 设置为 data 的副本, 其 url 成员设置为 对 url 执行 URL 序列化器 的结果。
  11. 如果由于安全原因阻止了某个文件类型, 则返回 一个被拒绝的承诺, 错误类型为 NotAllowedError DOMException
  12. this.[[sharePromise]] 设置为 一个新的承诺
  13. 返回 this.[[sharePromise]], 并 并行地:
    1. 如果没有可用的 共享目标, 则使用 global 在用户交互任务源上 排队一个全局任务
      1. 拒绝 this.[[sharePromise]], 错误类型为 AbortError DOMException
      2. this.[[sharePromise]] 设置为 null
      3. 终止此算法。
    2. 向用户展示一个或多个 共享目标 和中止操作的选项。此界面作为一个安全确认步骤, 确保网站无法静默地将数据发送到本地应用程序。用户代理 应该 显示中间界面,用户可以通过该界面验证共享的内容(如果操作系统级别的界面不提供此功能)。
    3. 等待用户的选择。
    4. 如果用户选择中止共享操作,使用 global 在用户交互任务源上 排队一个全局任务
      1. 拒绝 this.[[sharePromise]], 错误类型为 AbortError DOMException
      2. this.[[sharePromise]] 设置为 null
      3. 终止此算法。
    5. 激活所选的 共享目标data 转换为适合目标使用的格式, 并将转换后的数据传输到目标。
    6. 如果在启动目标或传输数据时发生错误,使用 global 在用户交互任务源上 排队一个全局任务
      1. 拒绝 this.[[sharePromise]], 错误类型为 DataError DOMException
      2. this.[[sharePromise]] 设置为 null
      3. 终止此算法。
    7. 一旦数据成功传输到 共享目标, 或成功传输到操作系统(如果无法确认传输到 共享目标), 使用 global 在用户交互任务源上 排队一个全局任务
      1. 解决 this.[[sharePromise]] 并返回 undefined
      2. this.[[sharePromise]] 设置为 null

2.1.3 canShare(data) 方法

当调用 canShare() 方法,并带有参数 ShareData data 时,执行以下步骤:

  1. documentthis相关全局对象关联的 Document
  2. 如果 document 不是 完全活动状态,则返回 false。
  3. 如果 document 没有 使用权限 "web-share", 则返回 false。
  4. 返回通过 验证分享数据data 以及 this相关设置对象API 基本 URL 的结果。
注意:canShare() 并不具备未来兼容性

2.1.4 验证共享数据

可共享的协议 是以下任何 URL协议

  • http
  • https
  • 任何用户代理支持共享的安全协议

要用 database验证共享数据,请执行以下步骤:

  1. 如果 data 的成员 titletexturlfiles 均不存在,返回 false。
  2. 如果 titletexturl 中的任意一个存在,将 titleTextOrUrl 设为 true。
  3. 如果 datafiles 成员存在:
    1. 如果 titleTextOrUrl 为 false,且 datafiles 成员为空,返回 false。
      注意

      这将导致 { files: [] } 字典被视为一个空字典。然而,传递像 {text: "text", files: []} 这样的字典是可以的,因为 files 只是被忽略。

    2. 如果实现不支持文件共享,返回 false。
    3. 如果用户代理认为共享 files 中的任何文件会导致潜在的恶意共享(例如,用户代理确定某个文件由于其内容、大小或其他特征是恶意的),返回 false。
  4. 如果 dataurl 成员存在:
    1. 运行 URL 解析器,解析 dataurl 成员,传入 base,不进行编码覆盖。
    2. 如果 url 解析失败,返回 false。
    3. 如果 url协议本地协议,或是 filejavascriptwswss,返回 false。
    4. 如果 url协议 不是 可共享的协议,返回 false。
  5. 返回 true。

2.2 ShareData 字典

WebIDLdictionary ShareData {
      sequence<File> files;
      USVString title;
      USVString text;
      USVString url;
    };

ShareData 字典包含若干可选成员:

files 成员
要共享的文件。
text 成员
构成共享消息主体的任意文本。
title 成员
被共享文档的标题,可能会被目标忽略。
url 成员
指向被共享资源的 URL 字符串。
注意

3. 共享目标

分享目标 是一个抽象概念, 指用户代理将分享数据传输到的目标位置。什么构成一个分享目标,取决于用户代理的决定。

一个分享目标可能无法直接接受 ShareData (因为它可能并未考虑到此 API)。但是,它 必须 能够接收与 ShareData 中所展示的一些或全部概念相匹配的数据。 为了将数据转换为适合目标接收的格式,用户代理应当ShareData 的成员映射到目标的等价概念上。 如果有需要,可以丢弃或合并成员。每个成员的含义由分享目标决定。

注意
ShareData 映射到分享目标(或操作系统)的 原生格式可能会有难度,因为某些平台没有对应的成员集。例如,如果目标具有“文本”成员而没有“URL”成员 (如在 Android 上的情况),一种解决方法是将 texturl 两个成员的内容连接起来并传递到目标的“文本”成员中。 ShareData

每个分享目标 可以 根据传递给 ShareData 的负载有条件地提供给 share() 方法。

3.1 共享目标示例

本节是非规范性的。

共享目标列表可以从多种来源填充,具体取决于用户代理和主机操作系统。例如:

注意
对于最后一种用例,正在尝试标准化接收共享数据的网站注册;请参见 Web Share Target

在某些情况下,主机操作系统将提供类似于 Web Share 的共享或意图系统。在这些情况下,用户代理可以简单地将共享数据转发到操作系统,而不直接与本机应用程序对话。

4. 权限策略集成

本规范定义了一个由字符串 "web-share" 标识的受策略控制的权限。 其 默认允许列表'self',这意味着第三方上下文默认不 被允许使用 该 API。

用户代理是否支持 权限策略 中的 Permissions-Policy HTTP 标头是 可选 的。

开发者可以使用 权限策略 规范提供的手段来控制第三方上下文是否和何时 被允许使用 此 API。

注意:权限策略的实现状态

5. 无障碍性考虑

本节为非规范性内容。

当本规范用于在用户界面中展示信息时,开发人员应遵循平台的操作系统级别无障碍指南。此外,鉴于共享可能对终端用户产生潜在的安全影响(如 share() 方法中所述),共享 UI 需要以无障碍的方式呈现,同时也要考虑平台的用户界面安全指南。一些关键的考虑因素包括:

这些元素的结合可以帮助具有视觉、运动或认知障碍的用户更好地理解网页所共享内容的性质。

6. 隐私考虑

7. 一致性

除了标记为非规范性的部分外,本规范中的所有编写指南、图表、示例和注释均为非规范性内容。除此之外,本规范中的所有内容均为规范性内容。

本文件中的关键词 MAYMUSTOPTIONALSHOULD 应按照 BCP 14 [RFC2119] [RFC8174] 进行解释,仅在这些关键词以大写形式出现时按照上述方式解释。

8. IDL 索引

WebIDLpartial interface Navigator {
      [SecureContext] Promise<undefined> share(optional ShareData data = {});
      [SecureContext] boolean canShare(optional ShareData data = {});
    };
    
    dictionary ShareData {
      sequence<File> files;
      USVString title;
      USVString text;
      USVString url;
    };

9. 变更日志

本节为非规范性内容。

以下规范性变更是在拟推荐标准阶段进行的。有关更改的完整列表,请参阅提交日志

自从规范发布为首次公开工作草案到候选推荐标准后,进行了以下规范性变更。有关更改的完整列表,请参阅提交日志

A. 致谢

编辑们要感谢以下 W3C 小组提供的宝贵反馈,这极大地改进了本规范: 无障碍平台架构工作组国际化工作组隐私兴趣组技术架构组

感谢 Web 意图 团队为 Web 应用互操作性用例打下了基础。特别感谢 Paul Kinlan 的早期倡导,他为 Web Share 贡献了许多早期的推广工作。

B. 参考文献

B.1 规范性参考文献

[fetch]
Fetch 标准。Anne van Kesteren。WHATWG。现行标准。网址:https://fetch.spec.whatwg.org/
[fileapi]
文件 API。Marijn Kruisselbrink。W3C。2023 年 2 月 6 日。W3C 工作草案。网址:https://www.w3.org/TR/FileAPI/
[html]
HTML 标准。Anne van Kesteren、Domenic Denicola、Ian Hickson、Philip Jägenstedt、Simon Pieters。WHATWG。现行标准。网址:https://html.spec.whatwg.org/multipage/
[PERMISSIONS-POLICY]
权限策略。Ian Clelland。W3C。2023 年 3 月 22 日。W3C 工作草案。网址:https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
在 RFC 中指示要求级别的关键词。S. Bradner。IETF。1997 年 3 月。最佳现行做法。网址:https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
RFC 2119 中关键词大小写不明确问题。B. Leiba。IETF。2017 年 5 月。最佳现行做法。网址:https://www.rfc-editor.org/rfc/rfc8174
[url]
URL 标准。Anne van Kesteren。WHATWG。现行标准。网址:https://url.spec.whatwg.org/
[WEBIDL]
Web IDL 标准。Edgar Chen、Timothy Gu。WHATWG。现行标准。网址:https://webidl.spec.whatwg.org/

B.2 非规范性参考文献

[encoding]
编码标准。Anne van Kesteren。WHATWG。现行标准。网址:https://encoding.spec.whatwg.org/