1. 简介
子应用 API 允许父应用以编程方式安装、列出和移除满足以下条件的辅助 应用(子应用):
-
对于操作系统和用户而言,它们表现为完全独立的应用(具有单独的启动器图标、 不同的任务栏/搁板窗口以及各自的操作系统集成)。
-
与父应用共享底层资源、源、存储、权限和更新生命周期。
此 API 仅限于隔离上下文,以确保安全性和数据完整性。
2. 概念
一个已安装 Web 应用具有关联的父应用,其值为 null 或一个已安装 Web 应用。
一个已安装 Web 应用具有关联的子应用集合,它是由集合形式保存的已安装 Web 应用。
一个 Document
具有关联的已安装 Web 应用,它是该 Document
作为其组成部分呈现的已安装 Web 应用。此关联的确切机制由实现定义。
如果一个 Document
具有关联的已安装 Web 应用,并且
其关联的已安装 Web 应用的
父应用不为 null,则该 Document
是一个子应用文档。
3. Window
接口的扩展
[Exposed =Window ,SecureContext ,IsolatedContext ]partial interface Window { [SameObject ]readonly attribute SubApps subApps ; };
3.1. subApps
属性
每个 Window
对象都有一个关联的 subApps,它是与该 Window
一同创建的 SubApps 实例。
4. SubApps
接口
// 表示 https://w3c.github.io/manifest/#id-membertypedef USVString ;ManifestId dictionary {SubAppsAddResponse record <USVString ,ManifestId >;installedApps record <USVString ,DOMException >; };failedApps dictionary {SubAppsRemoveResponse sequence <ManifestId >;removedApps record <USVString ,DOMException >; };failedApps dictionary {SubAppsListResult required DOMString ; }; [appName Exposed =Window ,SecureContext ,IsolatedContext ]interface {SubApps Promise <SubAppsAddResponse >(add sequence <USVString >);install_paths Promise <SubAppsRemoveResponse >(remove sequence <ManifestId >);manifest_ids Promise <record <USVString ,SubAppsListResult >>(); };list
如果满足以下所有条件,则字符串 path 是 Document
document 的有效相对路径:
-
path 不是有效的绝对 URL。
-
path 以
"/"开头。 -
path 不为空。
-
path 不以
"//"开头。
4.1. add()
方法
add(install_paths)
方法的步骤如下:
install_paths
参数是一个相对路径列表,这些路径指向子应用的起始 HTML 页面。
-
令 promise 为一个新的 promise。
-
令 document 为相关全局对象的关联 Document。
-
如果不允许 document 使用名为“策略控制特性“sub-apps”,则以一个“
SecurityError”DOMException拒绝 promise 并返回 promise。 -
如果 document 是一个子应用文档,则以一个“
NotSupportedError”DOMException拒绝 promise 并返回 promise。 -
令 parsedUrls 为空列表。
-
对于
install_paths中的每个 installPath:-
如果 installPath 不是 document 的有效相对路径,则以一个“
TypeError”DOMException拒绝 promise 并返回 promise。 -
令 absoluteUrl 为以 document 的文档基准 URL 作为基准 URL,解析 installPath 的结果。
-
如果 absoluteUrl 为失败,则以一个“
TypeError”DOMException拒绝 promise 并返回 promise。 -
将 absoluteUrl 追加到 parsedUrls。
-
-
令 parentApp 为 document 的关联的已安装 Web 应用。
-
如果
install_paths的大小大于 20,则以一个“QuotaExceededError”DOMException拒绝 promise 并返回 promise。 -
如果 currentSubAppsCount +
install_paths的大小大于 50,则以一个“QuotaExceededError”DOMException拒绝 promise 并返回 promise。 -
令 subApps 为此对象。
-
并行运行以下步骤:
-
令 userConsent 为请求用户同意安装
install_paths中子应用的结果(例如,通过呈现统一的安装对话框)。 -
如果 userConsent 被拒绝,则在 subApps 的相关全局对象上排入一个全局任务,以一个“
NotAllowedError”DOMException拒绝 promise, 并中止这些步骤。 -
令 installedApps 为空映射。
-
令 failedApps 为空映射。
-
对于 parsedUrls 中的每个 absoluteUrl:
-
令 installPath 为 absoluteUrl 的路径。
-
令 manifest 为给定 absoluteUrl 时获取并处理清单的结果。
-
如果 manifest 为失败,则执行以下步骤:
-
将 failedApps[installPath] 设置为一个新的“
DataError”DOMException。 -
继续。
-
-
令 manifestId 为 manifest 的 id。如果未 定义,则回退到 manifest 的 start_url(不含引用/散列片段)。
-
如果 parentApp 已安装具有 manifestId 的子应用, 则执行以下步骤:
-
将 failedApps[installPath] 设置为一个新的“
InvalidStateError”DOMException。 -
继续。
-
-
如果 parentApp 的清单的作用域是 manifest 的作用域的前缀,或者 manifest 的作用域是 parentApp 的子应用集合中任何当前已安装子应用的作用域的前缀,或者 parentApp 的子应用集合中任何当前已安装子应用的作用域是 manifest 的作用域的前缀,或者 absoluteUrl 指向 parentApp 的清单本身,则执行以下步骤:
-
将 failedApps[installPath] 设置为一个新的“
ConstraintError”DOMException。 -
继续。
-
-
尝试在平台的应用启动器中安装该子应用。
-
如果安装因系统或数据库错误而失败:
-
将 failedApps[installPath] 设置为一个新的“
OperationError”DOMException。 -
继续。
-
-
将 installedApps[installPath] 设置为 manifestId。
-
-
令 response 为一个新的
SubAppsAddResponse字典,其中:-
将
installedApps设置为 installedApps。 -
将
failedApps设置为 failedApps。
-
-
-
返回 promise。
4.2. remove()
方法
manifest_ids
参数是要移除的子应用的 id 列表。
remove(manifest_ids)
方法的步骤如下:
-
令 promise 为一个新的 promise。
-
令 document 为相关全局对象的关联 Document。
-
如果不允许 document 使用名为“策略控制特性“sub-apps”,则以一个“
SecurityError”DOMException拒绝 promise 并返回 promise。 -
如果 document 是一个子应用文档,则以一个“
NotSupportedError”DOMException拒绝 promise 并返回 promise。 -
令 parentApp 为 document 的关联的已安装 Web 应用。
-
令 parsedManifestIds 为空列表。
-
对于
manifest_ids中的每个 manifestId:-
如果 manifestId 不是 document 的有效相对路径,则以一个“
TypeError”DOMException拒绝 promise 并返回 promise。 -
令 parsedUrl 为以 document 的文档基准 URL 作为基准 URL,解析 manifestId 的结果。
-
如果 parsedUrl 为失败,则以一个“
TypeError”DOMException拒绝 promise 并返回 promise。 -
将 parsedUrl 追加到 parsedManifestIds。
-
-
令 subApps 为此对象。
-
并行运行以下步骤:
-
令 removedApps 为空序列。
-
令 failedApps 为空映射。
-
对于 parsedManifestIds 中的每个 parsedUrl:
-
令 manifestId 为 parsedUrl 的路径。
-
如果 parentApp 的子应用集合中不存在 已安装 Web 应用,且其 id 为 manifestId,则执行以下 步骤:
-
将 failedApps[manifestId] 设置为一个新的“
NotFoundError”DOMException。 -
继续。
-
-
尝试从系统启动器和注册表中卸载 ID 为 manifestId 的子应用。
-
如果卸载因系统错误而失败,则执行以下步骤:
-
将 failedApps[manifestId] 设置为一个新的“
OperationError”DOMException。 -
继续。
-
-
将 manifestId 追加到 removedApps。
-
-
令 response 为一个新的
SubAppsRemoveResponse字典,其中:-
将
removedApps设置为 removedApps。 -
将
failedApps设置为 failedApps。
-
-
-
返回 promise。
4.3. list()
方法
list()
方法的步骤如下:
-
令 promise 为一个新的 promise。
-
令 document 为相关全局对象的关联 Document。
-
如果不允许 document 使用名为“策略控制特性“sub-apps”,则以一个“
SecurityError”DOMException拒绝 promise 并返回 promise。 -
如果 document 是一个子应用文档,则以一个“
NotSupportedError”DOMException拒绝 promise 并返回 promise。 -
令 parentApp 为 document 的关联的已安装 Web 应用。
-
令 subApps 为此对象。
-
并行运行以下步骤:
-
令 listResult 为空映射。
-
从平台注册表中检索 parentApp 的所有当前已安装子应用的列表。
-
如果因平台错误而无法检索该列表,则在 subApps 的相关全局对象上排入一个全局任务,以一个“
OperationError”DOMException拒绝 promise, 并中止这些步骤。 -
对于每个已安装的子应用 subApp:
-
令 manifestId 为 subApp 的 id。
-
令 appName 为从该子应用的 Web 清单中提取的子应用名称。
-
令 resultEntry 为一个新的
SubAppsListResult字典,并将appName设置为 appName。 -
将 listResult[manifestId] 设置为 resultEntry。
-
-
-
返回 promise。
4.4. 获取并处理清单
编写“获取并 处理清单”算法。[议题 #2]
给定一个 url(一个 URL),要获取并 处理清单,运行以下步骤:
-
返回失败。
5. 安全和隐私注意事项
安装和管理辅助应用是一项强大特性。如果没有明确许可,用户代理不得允许 Web 应用 安装或管理子应用。
本节概述所考虑的威胁,以及用户代理为缓解这些威胁而必须遵循的规范性要求。
5.1. 共享源身份
子应用不具有独立的安全源。它与其父应用共享完全相同的源和本地数据存储(例如 Cookie、IndexedDB、LocalStorage 和 Cache Storage)。标准 Web 安全边界(例如同源策略)将父应用及其所有子应用视为单一实体。5.2. 权限继承
所有权限均由父应用及其子应用共享。向子应用授予某项权限(例如相机、文件 系统访问、USB)会自动将该权限授予父应用,反之亦然。要访问子应用 API,父应用的文档必须显式声明权限策略
sub-apps。为子应用声明的权限策略不起作用。
5.3. 明确的用户同意
必须针对特定源取得用户同意。调用add()
时,用户代理必须向用户呈现统一的安装对话框,其中显示所有请求安装的
子应用。如果一次添加多个子应用,则应在单个提示中呈现它们,以避免
对话框泛滥。
用户代理必须显示一个权限提示,清楚指出哪个源正在请求访问,并 向用户提供足够的信息以作出知情决定(例如,显示正在安装的子应用的名称 和图标)。
5.4. 身份欺骗风险
由于开发者可以自定义子应用的名称和图标,因此存在恶意应用 创建模仿系统对话框或受信任第三方应用的子应用的风险。 为缓解此风险,子应用 API 仅限于隔离上下文,这种上下文可保证完整性和签名验证。5.5. 操作系统集成扩展风险
子应用能够注册自己的操作系统集成(例如协议处理程序或文件类型 关联)。这意味着应用可能将其在操作系统中的影响范围扩展到远远超出 父应用主清单中声明的范围。 此风险因大多数操作系统集成都需要用户明确批准(例如, 选择子应用作为某种文件类型的默认应用)才能生效而得到缓解。5.6. 配额和限制
为了保护宿主操作系统和用户的应用启动器免受潜在的资源耗尽或滥用,平台 强制实施以下两个限制:-
每个父应用最多可安装 50 个子应用。
-
每次权限提示最多可安装 20 个子应用。
如果批量安装调用超出平台限制,则整个 add()
调用都会以一个“QuotaExceededError”
DOMException
拒绝。
6. 集成
6.1. 权限策略
本规范定义了一项特性,用于控制是否可以使用 Window
对象上的 subApps
属性所公开的方法。
此特性的特性名称是“sub-apps”。
此特性的默认允许列表为
'none'。用户代理可以针对特定源将其覆盖为
'self'(例如,根据用户的决定)。