本规范为 Web Application Manifest 扩展和孵化功能提供特性规范,这些功能 Chromium 已经发布,但 其他用户代理尚未承诺支持/实现。这些特性并非继续作为解释器保存, 而是在此处以更正式的方式记录。
这是一个非正式提案。
display_override 成员
对于高级用法,可以使用 [=manifest/display_override=] 成员来 指定 显示模式 列表值 的自定义后备顺序,以便 开发者为 Web 应用程序选择其首选的 显示模式。其 值是一个 [=display mode=]。
[=application manifest=] 的 [=manifest/display_override=] 成员是 序列,由 显示模式列表 值 组成, 包括 [=display mode/window-controls-overlay=] 和 [=display mode/unframed=] 等扩展。此成员表示开发者 对 [=display mode=] 的首选后备链。此字段会覆盖 [=manifest/display=] 成员。如果用户代理不支持此处指定的任何 [=display mode=],则会回退到考虑 [=manifest/display=] 成员。 算法步骤见处理 display 成员。
以下步骤会添加到 确定 Web 应用的选定显示模式 中的 [=application manifest/processing extension-point=]:
此成员旨在仅用于高级场景,在这些场景中, 开发者希望显式控制其显示模式的后备顺序,或者用于基本 显示模式 列表 中不可用的模式。否则,对于 大多数用例,[=manifest/display=] 成员已足够。
除了普通的 显示模式 之外, [=manifest/display_override=] 还支持其某些扩展。
下面展示了一个 [=manifest=],它相比
standalone 更偏好
minimal-ui 显示模式,
但如果不支持 minimal-ui,
则回退到 standalone,而不是
browser。
{
"name": "Recipe Zone",
"description": "All of the recipes!",
"icons": [{
"src": "icon/hd_hi",
"sizes": "128x128"
}],
"start_url": "/index.html",
"display_override": ["minimal-ui"],
"display": "standalone",
"theme_color": "yellow",
"background_color": "red"
}
[=app-region=] CSS 属性尚未在任何用户代理中实现, 因此它处于风险中。请注意,一些用户代理会将非标准 CSS 属性 `-webkit-app-region` 用于相同目的。
`app-region` 属性可用于通过 CSS 定义哪些区域或元素(例如标题栏中的区域或元素) 是可拖动的。
为了便于使用本规范添加的所有新扩展和孵化功能, 用户代理应在 [=processing a manifest=] 中的 扩展 点 期间运行以下内容(可访问 [=URL=] |document URL:URL|、[=URL=] |manifest URL:URL|、[=ordered map=] |json:ordered map| 和 [=ordered map=] |manifest:ordered map|):
tab_strip 成员
Web Application Manifest 的 `tab_strip` 成员是一个 对象,其中包含关于 应用程序在 [=display mode/tabbed=] 显示模式中预期如何行为的信息。 它具有以下成员:
home_tab 成员
[=tab_strip=] 对象的 `home_tab` 成员是一个有序映射, 其中包含关于一个特殊“主页标签页”的信息,该主页标签页 旨在作为应用程序的顶级菜单。它包含以下成员:
scope_patterns 成员是一个
{{URLPatternInput}} 列表,用于定义相对于 [=manifest URL=] 的
[=within home tab scope|主页标签页的作用域=]。
如果应用程序所应用的 [=display mode=] 是 [=display mode/tabbed=],且 [=Document/processed manifest=] 包含 [=tab_strip=] 成员的非 null [=home_tab=] 成员,则称该应用程序具有主页标签页。
主页标签页上下文是一个可选的 [=application context=],与其他应用程序上下文相比具有特殊属性。 如果应用程序 [=has a home tab=],每个应用程序窗口都应具有一个 [=home tab context=]。否则,应用程序窗口不应具有 [=home tab context=]。
[=home tab context=] 如何呈现由用户代理决定,但它应具有 不同于普通应用程序上下文的外观。
当且仅当满足以下条件时,称 [=URL=] |url:URL| 在主页标签页作用域内:
如果某 URL 不 [=within home tab scope=],则该 URL 在主页标签页作用域外。
如果应用程序 [=has a home tab=],则每当创建新的应用程序 窗口时(例如启动应用程序时,或将标签页移动到新窗口时), 用户代理必须在该窗口中创建一个新的 [=home tab context=]。 新创建的 [=home tab context=] 应被导航到 [=start URL=],该 URL 根据定义 [=within home tab scope=]。
当将与 [=home tab context=] 关联的 [=top-level traversable=] [=navigate|导航=] 到 [=outside of home tab scope=] 的 [=URL=] |url:URL| 时,运行以下步骤:
"_blank" 且 noopener 为 true 的可导航对象所得的结果。
当将具有 [=display mode/tabbed=] [=display mode=] 且不与 [=home tab context=] 关联的 [=top-level traversable=] (即非主页标签页)[=navigate|导航=] 到 [=within home tab scope=] 的 [=URL=] |url:URL| 时,运行以下步骤:
上述规则旨在确保以下不变量对于 [=has a home tab|具有主页标签页=] 的应用程序始终为真:
如果文档更改其 [=URL/fragment=],或使用 {{History}} API 将其显示 URL 修改为进入或离开主页标签页作用域,用户代理不会 在主页标签页和非主页标签页上下文之间动态移动文档,因为没有发生导航。 因此,上述不变量只关注文档创建时所具有的 [=Document/URLs=]。
对于通过修改其 URL 来“假装”导航的单页应用程序, 这可能导致不希望出现的行为,从而破坏上述不变量 (例如,如果用户在主页标签页中点击链接,将 URL 动态更改为非主页页面, 他们仍会停留在主页标签页内,因为实际上并没有导航)。 为避免这种情况,应用程序可以检测自己是否处于标签式应用程序模式, 并改变其行为,以执行真正进入和离开主页标签页作用域的导航, 而不是修改 URL。
new_tab_button 成员
[=tab_strip/new_tab_button=] 成员是一个有序映射, 用于描述一个 UI 便利项(例如按钮)的行为; 当该便利项被点击/激活时,会在应用程序窗口内打开一个新的 [=application context=]。它具有以下成员:
url 成员
是一个字符串,表示相对于 [=manifest URL=] 的 URL,
该 URL 是某个 [=Document/processed
manifest=] 的 [=manifest/within scope=]。
如果 [=Document/processed manifest=] 的 [=new_tab_button=] 的 [=new_tab_button/url=] 成员 [=outside of home tab scope=], 则应用程序具有新标签页按钮。如果应用程序不 [=has a new tab button|具有新标签页 按钮=],用户代理不应向最终用户提供“新建标签页”便利项。
当最终用户激活新标签页按钮时,运行以下步骤:
要处理 `tab_strip` 成员,给定 [=ordered map=] |json:ordered map|、[=ordered map=] |manifest:ordered map| 和 [=URL=] |manifest URL:URL|,在 [=processing a manifest=] 的 扩展点期间运行以下步骤:
要处理 `home_tab` 成员,给定 [=ordered map=] |json tab strip:ordered map|、[=ordered map=] |manifest tab strip:ordered map| 和 [=URL=] |manifest URL:URL|,运行 以下步骤:
要处理 `new_tab_button` 成员,给定 [=ordered map=] |json tab strip:ordered map|、[=ordered map=] |manifest tab strip:ordered map|、[=URL=] |manifest URL:URL| 和 [=URL=] |start URL:URL|,运行以下步骤:
要处理 `scope_patterns` 成员,给定 [=ordered map=] |json home tab:ordered map|、[=ordered map=] |manifest home tab:ordered map| 和 [=URL=] |manifest URL:URL|,运行以下步骤:
{
"name": "Tabbed App Example",
"start_url": "/",
"display": "standalone",
"display_override": ["tabbed"],
"tab_strip": {
"home_tab": {
"scope_patterns": [
{"pathname": "/"},
{"pathname": "/index.html"}
]
},
"new_tab_button": {
"url": "/create"
}
}
}
此示例是一个标签式 Web 应用;如果不支持标签式模式,
它会回退到单文档 standalone 窗口。任何到主索引页的导航
(即 / 或 /index.html)都会在
[=home tab context=] 中打开。新标签页按钮会在
/create 打开一个新标签页。
请注意,当与 [=tab_strip/home_tab/scope_patterns=] 进行匹配时,
URL 的 [=URL/query=] 部分默认会被忽略(因此到
/index.html?utm_source=foo 的导航会在
主页标签页中打开)。但是,当与 [=start URL=] 匹配时,
[=URL/query=] 必须完全匹配,因此希望忽略查询的站点
建议显式包含 [=start URL=] 的 [=URL/path=] 作为作用域模式。
`share_target` 成员将 Web 应用程序注册为共享操作的“目标” (例如,用于共享文本、URL 或文件)。 `share_target` 成员是 [[[web-share-target]]] 规范的一部分。
note_taking 成员
Web Application Manifest 的 `note_taking` 成员是一个 对象,其中包含 与记笔记相关的信息。它具有以下成员:
用户代理可以使用这些成员,将 Web 应用程序作为具有记笔记能力的 应用程序进行区别对待(例如,与操作系统记笔记界面集成)。
new_note_url
成员
[=note_taking=] `new_note_url` 成员是一个 [=string=], 表示开发者希望用户代理在用户想使用 Web 应用程序创建新笔记时 加载的 URL (例如,从操作系统快捷方式图标或键盘快捷键启动时)。
`new_note_url` 成员纯粹是建议性的,用户代理可以 忽略它,或向 最终用户提供是否使用它的选择。用户代理可以向最终用户提供 修改它的选择。
下面展示了一个记笔记应用程序的 [=manifest=]。
{
"name": "My Note Taking App",
"description": "You can take notes!",
"icons": [{
"src": "icon/hd_hi",
"sizes": "128x128"
}],
"start_url": "/index.html",
"display": "standalone",
"note_taking": {
"new_note_url": "/new_note.html"
}
}
要处理 `note_taking` 成员,给定 [=ordered map=] |json:ordered map|、[=ordered map=] |manifest:ordered map|、[=URL=] |manifest_URL:URL|,在 [=processing a manifest=] 的 扩展 点期间运行以下步骤:
要处理 `new_note_url` 成员,给定 [=ordered map=] |json_note_taking:ordered map|、[=ordered map=] |manifest_note_taking:ordered map|、[=URL=] |manifest_URL:URL|,运行 以下步骤:
要启动 `new_note_url`,给定 已处理清单 |manifest:processed manifest|,运行以下步骤:
用户代理可以随时为给定的 [=installed web application=] [=launch the `new_note_url`=],通常是响应用户便利项。
[=manifest's=] protocol_handlers 成员是一个
协议处理器描述数组,允许 Web 应用程序处理 URL 协议。
在安装时,用户代理应通过符合以下内容的交互, 向操作系统注册协议处理器:
要处理 `protocol_handlers` 成员,给定 [=object=] |json:JSON|、|manifest:ordered map|:
用户代理应在将 [=protocol handler description=] protocol_handlers 注册为宿主操作系统中某协议的 默认处理器之前请求用户许可。用户代理可以截断所呈现的 [=protocol handler description=] protocol_handlers 列表,以保持与宿主操作系统的惯例或限制一致。
每个 协议处理器描述 是一个 [=object=], 表示 Web 应用程序想要处理的协议,对应于 [=manifest/protocol_handlers=] 成员。它具有以下成员:
用户代理应使用这些值将 Web 应用程序注册为操作系统中的处理器。 当用户激活协议处理器 URL 时,用户代理应运行 处理协议启动。
[[HTML]] 的 {{NavigatorContentUtils/registerProtocolHandler()}} 允许
Web 站点将自身注册为特定协议的可能处理器。
对 协议处理器描述 而言,什么构成有效的
[=protocol handler
description/protocol=] 和 [=protocol handler description/url=]
值由该 API 定义。还请注意,[[HTML]] API 使用
scheme,而这里使用 [=protocol handler description/protocol=],
但适用相同的限制。
协议处理器描述 的 protocol 成员是一个
字符串,表示要处理的协议,例如 `mailto` 或
`web+auth`。
协议处理器描述 的
[=protocol handler description/protocol=] 成员等价于
[[HTML]] 中定义的 {{NavigatorContentUtils/registerProtocolHandler()}} 的
scheme 参数。
协议处理器描述 的 url 成员是相关协议
被激活时打开的应用程序 [=manifest/within scope=] 的
URL。
协议处理器描述 的 [=protocol handler description/url=]
成员等价于 [[HTML]] 中定义的
{{NavigatorContentUtils/registerProtocolHandler()}} 的
url 参数。
当具有 [=manifest=] manifest 的 协议处理器描述 protocol_handler 被调用时,它会经过与 [=invoke a protocol handler=] 相同的步骤;其中用户代理不是 [=navigating=] 到 resultURL,而是应 [=launch a web application=],传入 manifest 和 resultURL。
不应以这种方式调用并修改 [=invoke a protocol handler=]。 resultURL 的计算应被提取为一个单独的算法, 供通用使用。
根据操作系统能力,协议处理器可能会在用户没有明确知情的情况下 成为给定协议的“默认”处理器(例如自动处理给定协议的启动)。 为防止可能的滥用,用户代理可以采用如下保护措施:
如果用户代理移除协议处理器实体的注册,则应为用户提供 UX, 以便用户可重新向操作系统注册 Web 应用和协议。
[=manifest's=] file_handlers 成员是一个 [=list=],
它提供关于应用如何处理源自应用自身之外的文件打开操作的指令。
已注册文件处理应用程序的管理、呈现和选择由操作系统决定。
要处理 `file_handlers` 成员,给定 [=ordered map=] |json:ordered map|、[=ordered map=] |manifest:ordered map|、[=URL=] |manifest_url:URL|:
在 [=installation=] 时,用户代理应运行 [=register file handlers=] 的过程。
每个 文件处理器 表示 应用程序作用域内的一个 URL,该 URL 可处理带有其所接受 [=file types=] 的启动。它具有以下成员:
用户代理可以使用这些成员,在操作系统上将 Web 应用程序与 [=file type=] 关联。
文件类型可由 [=MIME type=] 和/或 [=file extension=] 定义。如果 OS 判定文件具有某个 [=MIME type=],和/或其名称以某个 [=file extension=] 结尾, 则该文件属于某个文件类型。文件扩展名是一个 以 "." 开头且只包含 有效 后缀代码 点的字符串。此外,[=file extensions=] 被限制为 16 个代码点的长度。
[=file handler=] 的 action 成员是一个 字符串,
表示相对于 manifest URL 的 URL,
该 URL 是某个 已处理
清单 的
[=manifest/within scope=]。在 [=execute a file handler
launch=] 的步骤中会导航到此 URL。
[=file handler=] 的 name 成员是一个 字符串,
用于向用户标识文件类型。[=User agents=] 可以在文件处理器
注册期间将此信息传递给操作系统。
文件处理器的 icons 成员列出作为
[=file type=] 图形表示的图标。用户代理可以在文件处理器
注册期间将此信息传递给操作系统。
[=file handler=] 的 accept 成员是一个 字典,
将 [=MIME types=] 映射到 [=file extensions=] 列表。
[=User agents=] 必须强制执行 [=file handler/accept=] 条目 仅适用于具有匹配扩展名的文件。
为了 [=register file handlers=],某些操作系统需要 [=MIME types=],某些则需要 [=file extensions=]。因此, 对于每个 [=file handler/accept=] 条目,清单必须始终同时提供两者。
除了完整的 [=MIME types=] 之外,"*" 可用作
[=MIME type=] 的子类型,以匹配例如
"image/*" 的所有图像格式(这些格式也要适用于
所提供的 [=file extensions=] 列表)。
[=file handler=] 的 launch_type 成员是一个
字符串,用于确定应用如何针对路由到此处理器的文件启动。
可能的值为 `"single-client"` 和
`"multiple-clients"`。如果未提供,则默认为
`"single-client"`。
当某个 [=file handler=] 被确定为匹配一组文件时, [=user agent=] 应使用 [=file handler/launch_type=] 来控制 应用是为每个文件启动一次 (`"multiple-clients"`),还是为所有文件启动一次 (`"single-client"`)。见 {{LaunchParams/files}}。用户代理 不得将来自不同 [=file handlers=] 的文件合并到 单个启动事件中。
要处理文件处理器项,给定 [=ordered map=] |item:ordered map|、[=URL=] |start_url:URL|、[=URL=] |scope:URL| 和 [=URL=] |manifest URL:URL|:
执行文件处理器启动的步骤由以下算法给出。 该算法接受 [=list=] |files:list| 和一个 [=ordered map=] |manifest:ordered_map|,该有序映射保存 [=processing a manifest=] 的结果。
用户代理应以与以下内容一致的方式,在宿主操作系统中 注册文件处理器:
用户代理可以截断 [=file extensions=] 的总集合,以保留功能并防止滥用。 用户代理可以阻止与某些文件类型建立关联。
根据操作系统能力,[=file handler=] 可能会在用户没有明确知情的情况下 成为给定 [=file type=] 的默认处理器,自动处理给定文件类型的启动。 为防止可能的误用,[=user agents=] 可以要求用户明确同意才开始 [=execute a file handler launch=] 的过程。如果请求同意,用户代理应允许用户指定该决定是永久的; 如果如此指定,则应移除 Web 应用程序作为文件处理实体的 OS 注册。
每个文件处理器的名称和图标可能涉及隐私和安全,因为没有指定 用户查看并确认这些内容的方式。因此,[=user agents=] 可以选择忽略 这些内容,转而使用替代字符串和图标,或回退到 OS 默认值。
在以下示例中,Web 应用程序具有 3 个不同的文件处理器。
相关应用程序是底层应用程序平台可访问的应用程序, 它与 Web 应用程序存在某种关系。
[=manifest's=] related_applications 成员列出相关
应用程序,并作为 Web 应用程序与相关应用程序之间
存在这种关系的指示。此关系是单向的,除非所列应用程序声称
存在相同关系,否则用户代理不得假定存在双向认可。
`related_applications` 的使用示例可以是爬虫利用该信息收集 关于 Web 应用程序的更多信息,或浏览器在用户想要安装 Web 应用程序时 建议所列应用程序作为替代。
要处理 `related_applications` 成员,给定 [=ordered map=] |json:ordered map| 和 [=ordered map=] |manifest:ordered map|:
[=manifest's=] `prefer_related_applications` 成员是一个
[=boolean=],用作给用户代理的提示,表示应优先使用
相关应用程序而不是 Web 应用程序。如果
`prefer_related_applications` 成员设置为 `true`,且用户代理想要
建议安装该 Web 应用程序,则用户代理可能想要改为建议安装其中一个
相关应用程序。
[=manifest's=] scope_extensions 成员表示应用程序期望的
[=scope extensions=] 列表。
作用域扩展通过描述应被视为 [=within extended scope=] 的额外 [=URLs=],扩展 [=manifest/navigation scope of a manifest=]。
用户代理必须先 [=process the scope_extensions member=] 并 [=validate scope extensions=],之后才能 [=apply extended scope=], 以允许额外的 [=URLs=] 被视为 [=within extended scope=]。
如果 |target| 是清单的 [=manifest/within scope=],或 [=matches a validated scope extension=], 则 [=URL=] |target:URL| 在扩展作用域内于 |manifest:processed manifest|。
如果给定 [=URL=] |target:URL| 和 [=list=] |validated_scope_extensions:list| 时,以下算法返回 `true`, 则 [=URL=] |target:URL| 匹配已验证的作用域扩展:
以下示例展示了一个使用 `scope_extensions` 成员的应用程序的 [=manifest=]。
{
"id": "https://example.com/app",
"name": "My App",
"icons": [{
"src": "icon/hd_hi",
"sizes": "128x128"
}],
"start_url": "/app/index.html",
"scope": "/app",
"display": "standalone",
"scope_extensions": [
{ "type": "origin", "origin": "https://example.co.uk" },
{ "type": "origin", "origin": "https://help.example.com" }]
}
下面展示了 2 个 [=web-app-origin-association=] 文件, 它们可从 `scope_extensions` 成员中列出的 [=origins=] 的 `.well-known` 路径下载。
{
"https://example.com/app": {
"scope": "/app"
}
}
{
"https://example.com/app": {
"scope": "/"
}
}
此应用的导航作用域由 [=URL/within scope=] 于以下任一 [=URLs=] 的 URL 构成: `https://example.com/app`、`https://example.co.uk/app` 和 `https://help.example.com`。
要处理 `scope_extensions` 成员,给定 [=ordered map=] |json:ordered map|、[=ordered map=] |manifest:ordered map| 和 [=URL=] |manifest_id:URL|:
要验证作用域扩展,给定 [=ordered map=] |extension:ordered map| 和 [=URL=] |manifest_id:URL|:
用户代理可以选择在某些场景中应用 应用扩展作用域,而在其他场景中应用 [=manifest/scope=]。
如果 [=application context=] 的 [=navigable/active document=] 的 [=URL=] 不是 [=manifest/within scope=],但 [=within extended scope=],则用户代理应提供 UI,允许用户确定该 [=URL=] 或至少其 [=origin=],包括它是否通过安全连接提供。该 UI 应区别于 当 [=URL=] 不是 [=application context=] 的 [=Document/processed manifest=] 的 [=manifest/within scope=] 时 使用的任何 UI,以便明显表明用户仍在导航该应用程序的预期内容, 但也让用户了解导航到不同 [=origin=] 的隐私和安全影响。
web-app-origin-association 文件是一个 JSON 文件, 可用于 [=validate scope extensions=] 或 [=validate origin migration=]。它确认其所在源与一个或多个 Web 应用程序之间的关联。 它通过引用清单 [=manifest/ids=] 来唯一标识应用。
给定 [=origin=] |origin:origin|,期望可从
[origin]/.well-known/web-app-origin-association
下载 [=web-app-origin-association=] 文件。
Web 应用程序源迁移允许 Web 应用程序向用户代理指示 它已从一个源移动到另一个源(在同一站点内)。这使用户代理能够 迁移已安装的 Web 应用程序,同时保留用户的安装状态以及可能的设置。
以下示例展示了托管在
https://old.example.com 的 Web 应用程序如何迁移到
https://new.example.com。两个源必须是
[=same site=],并且必须明确同意迁移。
首先,旧应用程序的清单可以可选地包含一个 `migrate_to` 成员,用于向用户代理发出其打算移动的信号 (或者旧应用程序可以重定向到新应用程序):
{
"name": "My App",
"id": "/",
"migrate_to": {
"id": "https://new.example.com/",
"install_url": "https://new.example.com/install"
}
}
接着,新应用程序的清单包含一个 `migrate_from` 成员, 用于声明从旧应用程序迁移:
{
"name": "My New App",
"id": "/",
"migrate_from": [
{
"id": "https://old.example.com/",
"install_url": "https://old.example.com/install",
"behavior": "force"
}
]
}
最后,旧源必须托管一个 `web-app-origin-association` 文件,以最终验证它允许新应用程序接管。没有此文件, 恶意的新应用程序可能会未经许可声称从旧应用程序迁移。
{
"https://new.example.com/": {
"allow_migration": true
}
}
migrate_from 成员
[=manifest/migrate_from=] 成员是一个由 [=strings=] 或 [=ordered maps=] 组成的 [=list=],用于标识正在从中迁移的 旧 Web 应用程序。
如果条目是 [=string=],则将其视为旧应用程序的 [=manifest/id=]。
如果条目是 [=ordered map=],它可以具有以下成员:
id:
表示旧应用程序 [=manifest/id=] 的 [=string=]。
install_url:一个 [=string=],
表示链接到旧应用程序清单的页面的 URL。用户代理可以使用此字段
获取旧应用程序的清单,以便即使旧应用程序的其他每个 URL
都重定向到新应用程序,也能应用更新。
behavior:
一个 [=string=],可以是 `"suggest"` 或 `"force"`。这是给用户代理的
提示,可能影响用户代理向用户呈现迁移相关 UI 的强制程度。
migrate_to 成员
[=manifest/migrate_to=] 成员是一个可选的 [=ordered map=], 用于主动发出向新应用程序迁移的信号。它具有以下成员:
id:
表示新应用程序 [=manifest/id=] 的 [=string=]。
install_url:一个 [=string=],
表示链接到新应用程序清单的页面的 URL。此页面上的清单需要包含
指向此应用程序的 [=manifest/migrate_from=] 字段,
才能处理迁移。
要验证源迁移,给定 [=URL=] |old_manifest_id:URL| 和 [=URL=] |new_manifest_id:URL|:
要处理 `migrate_from` 成员,给定 [=ordered map=] |json:ordered map|、[=ordered map=] |manifest:ordered map| 和 [=URL=] |manifest URL:URL|:
要处理 `migrate_to` 成员,给定 [=ordered map=] |json:ordered map|、[=ordered map=] |manifest:ordered map| 和 [=URL=] |manifest URL:URL|:
为防止恶意行为者静默接管应用程序(例如,一个简单计算器将自身更新为模仿银行应用), [=validate origin migration=] 算法强制执行双向握手。 新旧应用程序源都必须通过 [=web-app-origin-association=] 文件 明确同意迁移。
此外,迁移被限制为 [=same site=],以确保它们用于组织控制范围内 的合法品牌重塑和架构变更,而不是将所有权转移给未经验证的第三方。
用户代理应考虑将显式用户确认对话框作为迁移流程的一部分, 尤其是在包含对安全敏感字段(例如应用名称和图标)的更新时。
每个 外部 应用程序资源 表示一个与 Web 应用程序相关的应用程序。
[=external application resource=] 可以具有以下成员, 其中某些成员是成为 [=valid external application resource=] 所必需的:
有效外部应用程序资源必须具有 [=external application resource/platform=] 成员,以及 [=external application resource/url=] 或 [=external application resource/id=] 成员(或两者)。
platform 成员表示
此 [=external application resource=] 所关联的 [=platform=]。
平台 表示软件分发生态系统,
或可能表示操作系统。本规范不定义
platform 成员的具体值。
[=external application resource's=] url 成员是可以找到该应用程序的
URL。
要处理应用程序的 `url` 成员:
[=external application resource's=] id 成员表示
在平台上用于表示该应用程序的 id。
[=external application resource's=] min_version 成员
表示被认为与此 Web 应用相关的应用程序最低版本。此版本是一个
字符串,具有平台特定的语法和语义。
[=external application resource's=] fingerprints 成员
表示一个 [=fingerprints=] [=list=]。
指纹 表示一组用于验证 应用程序的加密指纹。指纹具有以下两个成员: type 和 value。二者都是 字符串,但其语法和语义由平台定义。
安装过程可以通过多种方式触发:
无论哪种情况,如果文档不可安装,用户代理都不得 呈现安装提示。
用户代理可以在任何时候(仅当文档可安装时) 运行通知安装提示可用的步骤, 从而让站点有机会显示站点触发的 安装提示,而无需用户与用户代理 UI 交互。
要呈现 安装提示:
通知安装提示可用的步骤由以下算法给出:
安装 Web 应用程序的步骤由以下算法给出:
按设计,本规范不向开发者提供显式 API 来“安装” Web 应用程序。相反,manifest 可作为给用户代理的 可安装性信号,表示 Web 应用程序可以被安装。 这些信号会因用户代理而异,因为每个用户代理都有自己的启发式方法 来确定 Web 站点是否符合安装提示的条件。实现者通常会提供文档, 描述其特定的可安装性信号,或 Web 应用程序需要满足的其他相关标准, 以便被视为可安装。
用户代理可能为 Web 应用程序实现的可安装性信号示例:
此列表并非详尽无遗,某些可安装性信号 可能并不适用于所有用户代理。用户代理如何利用这些 可安装性信号 来确定 Web 应用程序是否可安装, 留给实现者决定。
本规范的 [=event|事件=] 依赖于 application life-cycle task source。
[Exposed=Window]
interface BeforeInstallPromptEvent : Event {
constructor(DOMString type, optional EventInit eventInitDict = {});
Promise<PromptResponseObject> prompt();
};
dictionary PromptResponseObject {
AppBannerPromptOutcome userChoice;
};
enum AppBannerPromptOutcome {
"accepted",
"dismissed"
};
当允许站点呈现站点触发的安装提示时, 或者在用户代理呈现自动安装提示之前, 会分派 {{BeforeInstallPromptEvent}}。它允许站点取消 自动安装提示,并手动呈现 站点触发的安装提示。
PromptResponseObject 包含调用 {{BeforeInstallPromptEvent/prompt()}} 的结果。它包含一个成员, userChoice, 该成员表示用户选择的结果。
{{BeforeInstallPromptEvent}} 实例具有以下内部槽:
prompt() 方法
当调用 prompt 方法时,运行以下步骤:
要使用 {{BeforeInstallPromptEvent}} event 请求呈现安装提示:
此示例展示了如何阻止自动安装提示显示,直到用户点击按钮来显示 站点触发的安装提示。这样,站点可以将安装留给用户自行决定 (而不是在任意时间提示),同时仍提供醒目的 UI 来执行安装。
window.addEventListener("beforeinstallprompt", event => {
// 抑制自动提示。
event.preventDefault();
// 显示(默认禁用的)安装按钮。此按钮在点击时
// 解析 installButtonClicked promise。
installButton.disabled = false;
// 等待用户点击按钮。
installButton.addEventListener("click", async e => {
// prompt() 方法只能使用一次。
installButton.disabled = true;
// 显示提示。
const userChoice = await event.prompt();
console.info(`user choice was: ${userChoice}`);
});
});
AppBannerPromptOutcome 枚举
AppBannerPromptOutcome 枚举的值表示 呈现安装提示后的结果。
partial interface Window {
attribute EventHandler onappinstalled;
attribute EventHandler onbeforeinstallprompt;
};
onappinstalled 属性
onappinstalled 事件处理器 IDL 属性 处理 "appinstalled" 事件。
onbeforeinstallprompt 属性
onbeforeinstallprompt 事件处理器 IDL 属性处理 "beforeinstallprompt" 事件。