iOS 添加到主屏幕:iOS PWA 安装
发布于 更新于
一句话: 在 iOS 与 iPadOS 上,安装 PWA 的唯一途径是用户自己的手势——点按分享, 再点按“添加到主屏幕”。没有可挂接的安装事件,也没有你能触发的提示。你的标记提供的是默认值 与素材——图标、默认名称、清单——而名称由用户在添加时编辑;在 iOS 26 上,图标如何启动则由 用户的“以 Web 应用打开”开关决定。
自第一代 iPhone 起,用户就可以把任意网站添加到主屏幕。在 iOS 与 iPadOS 的 Safari 中, 流程是:点按分享按钮打开分享菜单,然后点按**“添加到主屏幕”**。该网站的图标随即出现在 主屏幕上,轻点一下就能回到站点。用户在添加时还可以修改应用的名称。
没有程序化的替代方案。beforeinstallprompt——其他平台在提示用户把站点安装到主屏幕之前
触发的那个事件——是非标准的,且被标注为可用性有限,因此这里没有任何东西可供拦截、延迟或
重新触发。
第三方浏览器同样可以安装
Section titled “第三方浏览器同样可以安装”iOS 与 iPadOS 16.4 让第三方浏览器也能在分享菜单中提供“添加到主屏幕”。WebKit 明确记录了 该菜单项出现所需满足的条件:
- 应用持有
com.apple.developer.web-browser托管授权; - 分享菜单的
activityItems数组中包含一个WKWebView; - 该
WKWebView正在显示 HTTP 或 HTTPS URL 的文档; - 若设备是 iPad,则它未被配置为共享 iPad。
是 Web 应用,还是书签
Section titled “是 Web 应用,还是书签”用户点按生成的图标后会发生什么,在 16.4 与 26 之间发生了实质变化。
在 iOS 与 iPadOS 16.4 上,只要网站的清单把 display 成员设为 standalone 或
fullscreen,它就会以 Web 应用方式打开——无论是哪个浏览器添加的——并在 App 切换器中
拥有独立于 Safari 的预览。如果既没有请求 Web 应用行为的清单,也没有把站点标记为
web-app-capable 的 meta 标签,该条目会保存为主屏幕书签;自 16.4 起,这类书签会在用户当前的
默认浏览器中打开。
在 iOS 26 与 iPadOS 26 上,WebKit 修改了这一行为:默认情况下,添加到主屏幕的每一个 网站都以 Web 应用方式打开。更想要浏览器书签的用户,可以在添加时关闭“以 Web 应用打开”—— 即便站点本身被配置为 Web 应用。WebKit 的表述很直白:Safari 中现在对“可安装性”已没有任何 要求,用户可以把任意站点添加到主屏幕并以 Web 应用方式打开它。决定权从你的标记转移到了 拿着手机的那个人手里。
这并没有移除任何支持。WebKit 明确指出,清单带来的好处依然生效——在清单中声明图标,它们 就会被使用——只是让用户获得 Web 应用体验不再需要清单文件;正如 iOS 与 iPadOS 的主屏幕 Web 应用从来不像其他平台的 PWA 那样要求 Service Worker。
图标、名称与启动图
Section titled “图标、名称与启动图”- 清单图标自 iOS 与 iPadOS 15.4 起即受支持。 你也可以沿用在文档头中列出
apple-touch-icon链接这一长期做法——如果两者都提供,apple-touch-icon优先于 清单声明的图标。 - 不提供图标,系统会替你造一个。 过去 iOS 会用站点截图生成图标;16.4 改为用站点名称的 首字母加上取自站点的颜色生成一个字母图标。
- 为触摸图标设定尺寸。 Apple 的指南建议把
apple-touch-icon.png放在根文档目录作为 全站图标,或用sizes声明分页面图标;系统使用最贴近设备合适尺寸的图标,其次是大于该 尺寸中最小的那个,再次是可用图标中最大的那个。 - 启动图。 默认情况下,应用启动时显示的是它上次启动时的截图;
<link rel="apple-touch-startup-image" href="/launch.png">可覆盖它。这在 Web 应用离线时 尤其有用。 - 启动图标标题。 默认使用
<title>标签;<meta name="apple-mobile-web-app-title" content="AppTitle">可设置不同的名称。
<!-- 全站图标,以及一个针对设备的覆盖项 --><link rel="apple-touch-icon" href="/touch-icon-iphone.png"><link rel="apple-touch-icon" sizes="180x180" href="/touch-icon-iphone-retina.png">
<!-- Web 应用启动时显示的启动图 --><link rel="apple-touch-startup-image" href="/launch.png">
<!-- 主屏幕图标下方的名称 --><meta name="apple-mobile-web-app-title" content="AppTitle">旧版 apple- 独立模式标签
Section titled “旧版 apple- 独立模式标签”Apple 的存档指南描述了清单出现之前的机制。理解它仍有价值,因为你会在旧代码和旧建议中 遇到它:
把
apple-mobile-web-app-capablemeta 标签设为yes以开启独立模式。
在那个存档模型中,独立模式意味着不使用 Safari 来显示网页内容——顶部没有 URL 输入框、
底部没有按钮栏,只保留状态栏——并且 apple-mobile-web-app-status-bar-style
“除非你先按上述方式指定独立模式,否则不起作用”。WebKit 自己的历史记述把这个标签定位在
2008 年 8 月的 iPhone OS 2.1;Web 应用清单自 2013 年开始标准化,Safari 于 2018 年 3 月
随 iOS 11.4 采纳。
请把这层依赖关系当作有据可查的历史行为来读,而不是今天仍在决定独立模式的规则:在 iOS 26 与 iPadOS 26 上,决定主屏幕条目是否以 Web 应用打开的是“以 Web 应用打开”开关, 无论标记怎么写。
<!-- 旧版独立模式,如 Apple 存档指南所述 --><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><!-- "black" 是 Apple 存档指南所演示的取值 -->检测显示上下文
Section titled “检测显示上下文”你无法询问用户能否安装——因为不存在安装事件。你能询问的是页面此刻以何种方式显示, 而这正是真正有意义的分支。可用的检查有两种:
window.navigator.standalone是 Apple 指南所记载的只读布尔属性,用于判断网页是否正以 独立模式显示。- 标准的
display-mode媒体特性用于测试 Web 应用是显示在普通浏览器标签页中,还是以独立 应用、全屏等其他方式显示。它的值标识浏览器实际采用的模式,可能与清单请求的模式不同。
// 优先使用标准媒体特性;回退到 Apple 的旧属性。const standalone = ('standalone' in window.navigator && window.navigator.standalone === true) || window.matchMedia('(display-mode: standalone)').matches;
if (standalone) { hideInstallHint(); // 正以独立模式显示——无需再教学} else { // iOS 上不存在安装事件,唯一的"提示"就是你自己的文案。 showShareMenuInstructions(); // "点按分享,然后添加到主屏幕"}请在用户访问过几次之后再显示该提示,而不是首次加载就弹出;并且绝不要在页面正以独立模式 显示时渲染它——在已启动的 Web 应用里出现安装横幅纯属噪音。
主屏幕 Web 应用的能力支持
Section titled “主屏幕 Web 应用的能力支持”| 能力 | iOS / iPadOS | 说明 |
|---|---|---|
| 添加到主屏幕 | 支持,经分享菜单 | Safari 自第一代 iPhone 起;第三方浏览器自 16.4 起。 |
beforeinstallprompt |
不支持 | 非标准、可用性有限——没有程序化安装。 |
| 以 Web 应用方式打开 | 支持 | 16.4 上需清单 display: standalone/fullscreen;iOS 26 上每个添加的站点默认如此。 |
| App 切换器条目 | 支持 | Web 应用与 Safari 分开预览。 |
| Service Worker | 支持,但非必需 | 主屏幕 Web 应用从不要求它;原始 Web Push 需要,Declarative Web Push(18.4+)不需要。 |
| Web Push | 支持(16.4+),仅主屏幕 Web 应用 | 请求必须响应直接用户交互。18.4 起 Declarative Web Push 额外提供 window.pushManager。 |
| Badging API | 支持(16.4+),仅主屏幕 Web 应用 | 用户允许通知后,图标上才出现计数。 |
清单 id |
支持(16.4+) | 与用户所取名称组合,标识每一份安装。 |
清单 icons |
支持(15.4+) | 若同时存在,apple-touch-icon 优先。 |
| 屏幕唤醒锁 / 屏幕方向 / 用户激活 | 支持(16.4+) | WebKit 将其列为 16.4 面向 Web 应用开发者的新能力。 |
| 默认持久存储 | 不支持 | 除非源主动申请,存储都是尽力而为。 |
各浏览器的分特性数据,请查看 /zh/compatibility/。
可多次安装是特性,不是缺陷
Section titled “可多次安装是特性,不是缺陷”iOS 从一开始就支持同一个 Web 应用安装多次,WebKit 把它视为有意为之:多账号、工作与个人
分离等等。自 16.4 起,清单的 id 成员——一个 URL 形态的 Web 应用唯一标识符——会与用户添加
时输入的名称组合起来,使每份副本都可区分。这正是“专注模式”能只静音“Shiny(个人)“而放行
“Shiny(工作)“的原因;当用户在多台设备上给同一站点取相同名称时,专注设置也因此得以同步。
显式声明 id 依然值得做:web.dev 的论点是,显式的 id 直接定义了标识符,使其不再依赖
start_url 或清单文件所在的位置。
实践检查清单
Section titled “实践检查清单”- 自行提供“点按分享,然后添加到主屏幕”的说明——没有任何浏览器 UI 会替你提示。
- 按
(display-mode: standalone)分支(以navigator.standalone作为旧版回退),绝不要按 User-Agent 字符串。 - 在清单中声明图标,同时清楚一个随手留下的
apple-touch-icon会覆盖它们。 - 设置清单
id,让多次安装可区分、专注设置可同步。 - 不要依赖
apple-mobile-web-app-capable在 iOS 26 上决定 Web 应用模式——由用户的“以 Web 应用打开”开关决定。 - 即便主屏幕条目不要求 Service Worker,也要注册一个;原始 Web Push(16.4+)需要它。Declarative Web Push(18.4+)则通过
window.pushManager订阅,无需 Service Worker。 - 把已存数据当作尽力而为:它在该源未超配额、设备仍有空间、且用户没有清除数据时才会保留;而且在开启跨站跟踪保护时,若某个源在最近七天的浏览器使用中没有点击或轻点,Safari 会主动删除它由脚本创建的数据。
navigator.storage.persist()是主动申请的入口,而 Safari 会依据交互历史自动作答,不向用户显示提示。 - 在真机上测试——上述行为都是主屏幕行为,不是标签页行为。
下一步去哪里
Section titled “下一步去哪里”- iOS 与 Safari 上的 PWA —— 应用进入主屏幕之后, 整个 WebKit 平台的全貌。
- iOS Safari 推送 —— 依赖这一安装步骤的 16.4 Web Push 配置。
- 角标 —— 主屏幕图标上的
setAppBadge/clearAppBadge。 - 可安装性标准 —— 其他平台在愿意提供 安装之前要求什么。