# iOS 18.6.2 主屏 Web 应用真机实测

> 在一台 iOS 18.6.2 的 iPhone 16 Pro 上逐步实测主屏 Web 应用：显示模式、Cookie 与存储、状态栏、notificationclick 与推送，脱敏后的数据公开。

import Figure from '@components/Figure.astro';

iOS 18.6.2 上的主屏 Web 应用在实测中拿到了 Safari 的 Cookie 副本，也能处理通知点按。2026-10-20，我们用一台 iPhone 16 Pro（版本号 22G100，Safari 18.6）测了三个小时，逐项检查 11 个问题，当晚又补测了状态栏颜色。多数结果印证了 WebKit 或社区笔记已有的描述，并留下这个版本的测量值；前期检索没有找到另外两项结果的公开记录。

测试涉及应用启动、图标选择、Safari 数据复制、屏幕顶部布局与颜色，还检查了通知权限、推送订阅、`notificationclick` 和角标是否按文档工作。OpenPWA 的一名操作者把测试页面加到手机主屏幕并打开，还点按了通知、截了图。每完成一步，智能体就用 USB 读取页面状态。脱敏后的证据以 CC BY 4.0 公开在[数据包](/zh/research/2026-10-ios18-home-screen-web-apps/data/)里。

:::note
设备上的每一步都由 OpenPWA 的一名操作者在真实 iPhone 上完成。读数采集、截图与录屏分析以及本文写作由 AI 智能体会话完成，并经过站点自动化门禁检查；没有人逐条签核（见[编辑流程](/zh/about/editorial/)）。引用数据时写作「OpenPWA device test, 2026-10-20, iPhone 16 Pro, iOS 18.6.2 (22G100)」，引用单个发现时加上实验记录条目号，例如 N35。
:::

## 18.6.2 上的实测结果

没有 manifest 和图标的页面加到主屏幕后，仍在 Safari 中打开，使用 Safari 的存储，没有以 Web 应用运行。一个第一方 Cookie 在每个新主屏应用创建时从 Safari 复制过去一次，之后各自独立；localStorage 与 IndexedDB 都没有复制过去。这在 18.6.2 上重现了 WebKit 对 iOS 17.2 的描述。在已安装应用中，`notificationclick` 在全部 6 次点按中同时经由 `addEventListener` 与 `onnotificationclick` 属性触发，每次都有存活的窗口可以聚焦。`'onnotificationclick' in self` 在由已安装应用控制的 Service Worker 中为 `true`，在由 Safari 标签页控制的同一个 worker 中为 `false`，这可以解释 browser-compat-data（BCD）里的「不支持」记录。在一个从未请求过权限的应用里，权限请求挂起了 2068 ms，直到操作者回应可见的系统提示。Service Worker 作用域为子路径时，注册上已有订阅，`window.pushManager.getSubscription()` 却返回 `null`，这与 WebKit「只有根作用域的 worker 与 window 共享订阅」的规则一致。使用默认状态栏样式时，页面上方是一条纯色条带，页面内容始终到不了那里；条带颜色在页面有 `theme-color` meta 时取自它，否则取自 manifest 的 `theme_color`。`black-translucent` 加 `viewport-fit=cover` 则把页面画到状态栏之下（[REPORT.md](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/REPORT.md)，openpwa.net）。

## 主屏应用需要单独测试的意义

自 iOS 16.4 起，站点的 manifest 只要将 `display` 设为 `standalone` 或 `fullscreen`，添加到主屏幕后就会以 Web 应用打开。这样的应用能用 Web Push、通知和 Badging API，Safari 标签页则没有这些能力（[Web Push for Web Apps on iOS and iPadOS](https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/)，webkit.org）。启动方式会影响可用接口、页面读到的存储、屏幕顶部的绘制，以及通知事件能否到达 Service Worker。只在 Safari 标签页里测试或检测特性，就漏掉了已安装应用的运行场景。

两处资料分歧促成了这次测试。BCD 把 `ServiceWorkerGlobalScope` 上的 `notificationclick` 记为 iOS 版 Safari 不支持，而一个长期未关闭的 BCD issue 报告该事件在已安装应用中会触发（[mdn/browser-compat-data#22959](https://github.com/mdn/browser-compat-data/issues/22959)，github.com）。OpenPWA 自己的[主屏存储隔离](/zh/reference/storage/home-screen-storage-isolation/)页面曾告诉读者，在 Safari 中写入的登录令牌在已安装应用中不存在，而 WebKit 的 Safari 17.2 文章记载，创建应用时会复制 Cookie（[WebKit Features in Safari 17.2](https://webkit.org/blog/14787/webkit-features-in-safari-17-2/)，webkit.org）。我们在设备上实测了这两个问题，并据此更正了存储隔离条目。

这次运行也是一份基线。同一台手机之后会升级到 iOS 27，再复查同一批页面；而一旦升级，iOS 18.6.2 的状态就再也测不到了。有一期技术周刊写道，iOS 27 上已安装应用会在状态栏下渲染模糊效果，`theme-color` 与 `apple-mobile-web-app-status-bar-style` 在那里都没有作用（[So what's up with the iOS27 blur?](https://modernwebweekly.substack.com/p/so-whats-up-with-the-ios27-blur)，modernwebweekly.substack.com）；18.6.2 的测量值可供对照。

## 已有记录

结果注明了哪些印证已有描述，哪些属于新发现。前期检索查阅了 WebKit 的版本文章、BCD 及其 issue 讨论、文中提到的 WebKit 缺陷，以及 Maximiliano Firtman 关于 iOS 上 PWA 支持情况的笔记，笔记更新于 2026-10-13（[iOS PWA Compatibility](https://firt.dev/notes/pwa-ios/)，firt.dev）。

### 厂商文档

WebKit 以 manifest 定义主屏 Web 应用；没有 manifest、也没有 `apple-mobile-web-app-capable` meta 标签时，站点会存成书签，在默认浏览器中打开（[Web Push for Web Apps on iOS and iPadOS](https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/)，webkit.org）。自 iOS 26 起，添加到主屏幕的站点默认都以 Web 应用打开，除非用户关闭「Open as Web App」（[WebKit Features in Safari 26.0](https://webkit.org/blog/17333/webkit-features-in-safari-26-0/)，webkit.org），所以 18.6.2 上的这次运行是 26 之前的对照组。

存储方面，WebKit 的跟踪防护页面写道「the website data of home screen web applications is kept isolated from Safari」（[Tracking Prevention in WebKit](https://webkit.org/tracking-prevention/)，webkit.org），WebKit 181849 号缺陷下的回复称这种分隔是「by design」（[Bug 181849](https://bugs.webkit.org/show_bug.cgi?id=181849)，bugs.webkit.org）。Safari 17.2 文章为 Cookie 收窄了这条规则：用户点按「添加到主屏幕」创建 Web 应用时，「the cookies are copied over, including the information about login state」，「No other kind of local storage is copied over」，并且「After a user adds a web app to the Home Screen or Dock, no other website data is shared」（[WebKit Features in Safari 17.2](https://webkit.org/blog/14787/webkit-features-in-safari-17-2/)，webkit.org）。

声明式 Web Push 自 iOS 与 iPadOS 18.4 起加入 `window.pushManager`，页面无需 Service Worker 即可订阅（[WebKit Features in Safari 18.4](https://webkit.org/blog/16574/webkit-features-in-safari-18-4/)，webkit.org）。WebKit 介绍它的文章补充：「If you do also have a registered service worker scoped to the root level of your website domain, it shares the same push subscription as the window object」（[Meet Declarative Web Push](https://webkit.org/blog/16535/meet-declarative-web-push/)，webkit.org）。

屏幕顶部方面，Apple 已归档的 meta 标签参考写道，取值为 `default` 或 `black` 时「the web content is displayed below the status bar」，取值为 `black-translucent` 时「the web content is displayed on the entire screen, partially obscured by the status bar」（[Supported Meta Tags](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html)，developer.apple.com）。Safari 15 加入了 `theme-color`，用来改变「the color of the status bar and overscroll area in Safari on iOS 15」（[New WebKit Features in Safari 15](https://webkit.org/blog/11989/new-webkit-features-in-safari-15/)，webkit.org）。Web Application Manifest 把 `theme_color` 定为应用上下文的默认主题色，并允许用户代理用作用域内文档的 `theme-color` meta 元素覆盖它，但不要求这样做（[Web Application Manifest](https://www.w3.org/TR/appmanifest/)，w3.org）。

### 兼容性数据与缺陷报告

BCD 的 `ServiceWorkerGlobalScope.json` 把 `safari_ios` 上的 `notificationclick_event` 记为 `version_added: false`（[BCD api/ServiceWorkerGlobalScope.json](https://github.com/mdn/browser-compat-data/blob/main/api/ServiceWorkerGlobalScope.json)，github.com）。在 2024 年提交、2026-10-20 仍未关闭的 #22959 中，一位 BCD 贡献者解释说，采集器在 Service Worker 中检查 `"onnotificationclick" in self`，这一检查在 iOS 16、17、18 的 Safari 上都失败，而该属性受一个 WebKit 偏好设置控制；另有参与者报告事件在已安装应用中会触发（[mdn/browser-compat-data#22959](https://github.com/mdn/browser-compat-data/issues/22959)，github.com）。WebKit 268797 号缺陷「notificationclick events in serviceworkers not firing」仍为 NEW 状态，其中有报告称用户点按通知时如果应用没有存活页面，事件不触发（[Bug 268797](https://bugs.webkit.org/show_bug.cgi?id=268797)，bugs.webkit.org）。BCD 把 `api.Window.pushManager` 记为 iOS 版 Safari 18.4 起支持，附注说通知只在保存到主屏幕的 Web 应用中可用，但没有说明普通标签页中是否暴露该对象（[BCD api/Window.json](https://github.com/mdn/browser-compat-data/blob/main/api/Window.json)，github.com）。

### 社区笔记

Firtman 的笔记记载：自 17.2 起登录 Cookie 会复制到已安装应用，存储不与浏览器共享；`apple-touch-icon` link 元素会覆盖 manifest 中的图标声明；自 iOS 15 起不建议用 `apple-mobile-web-app-status-bar-style`，改用 `theme-color` meta 标签；`black-translucent` 仍是「Still the only way to get a fullscreen app」（[iOS PWA Compatibility](https://firt.dev/notes/pwa-ios/)，firt.dev）。我们在 18.6.2 上测试了其中几项行为。

### 这次测试补上了什么

Cookie 复制、`notificationclick` 在已安装应用中触发、`black-translucent` 让页面铺满全屏，以及图标与 manifest 的规则，此前都有记录。这次测试补上了具体版本和日期下的测量值。有两项结果在公开资料里没有找到：`'onnotificationclick' in self` 在由已安装应用控制的 worker 中为 `true`，在由 Safari 标签页控制的同一个 worker 中为 `false`；`window.pushManager` 在普通 Safari 标签页中存在，而那里没有 `Notification` 与 `PushManager`。默认状态栏在 18.x 上的几何测量值（下移 62 px、874 CSS px 中占 812、纯色条带）此前也没有公开，尽管它所测的行为是有记录的（[FINDINGS.md](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/FINDINGS.md)，openpwa.net）。

## 方法

判断结果时，我们优先采用页面读数，其次是截图，最后才是口头描述。测试报告逐步给出了操作流程、工具哈希与测试页面的提交记录（[REPORT.md](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/REPORT.md)，openpwa.net）。

### 设备与主机

测试用了一台 iPhone 16 Pro（ProductType iPhone17,1），运行 iOS 18.6.2，版本号 22G100，正式版通道，Safari 18.6，浏览器语言 zh-CN，因此系统提示以中文显示。外观为浅色，06:54 到 09:31 UTC 之间的每次仪器读数都报告 `prefers-color-scheme: dark` 为 false。Web 检查器与远程自动化均已开启。手机没有抹掉重置，装有其他网站的主屏应用，并装有至少一个 Safari Web 扩展；功能开关、VPN 与 iCloud 专用代理的状态没有记录。主机是运行 macOS 26.3 的 Mac，用 USB 连接手机，使用 `safaridriver` 与 `ios_webkit_debug_proxy` 1.9.2（[ios-webkit-debug-proxy](https://github.com/google/ios-webkit-debug-proxy)，github.com）。

### 测试页面

所有页面都由 openpwa.net 提供。[演示应用](/demo/)可安装，`id`、`start_url` 与 `scope` 都是 `/demo/`，有语言切换、推送和角标页面，语言设置存在 localStorage 里。设备实验室（位于 `/lab/` 下，不收录）是第二个可安装应用，有自己的 manifest 与 Service Worker，另外还有：

- 一个探测页面，没有 manifest、图标、主题色，也没有 Service Worker；
- 一个只有 manifest 的应用，带 manifest 图标、没有 apple-touch-icon；
- 标明来源的图标（红色「180 apple-touch」、蓝色「192 manifest any」）；
- 几个会打印自身几何数据的状态栏变体（baseline、fixed、sticky、safe-area），以及一个单独安装、带 `apple-mobile-web-app-status-bar-style: black-translucent` 的应用；
- 一个通知记录器，其 Service Worker 用 `addEventListener` 与 `self.onnotificationclick` 两种方式注册 `notificationclick`，各自往 IndexedDB 写一条记录；
- 一个写入 localStorage、IndexedDB 与 Cookie（`Secure`、`SameSite=Lax`，由 `document.cookie` 设置）的存储标记；
- 一个单独的、从未请求过权限的应用「Perm Test」，用 `performance.now()` 给 `Notification.requestPermission()` 计时；
- 补测用的三个应用（M1 至 M3），它们的 manifest `theme_color` 与页面 `theme-color` 互不相同或缺失。

主测试中每个 manifest 都声明 `theme_color` 为 `#161616`，除探测页面和一个红色变体外，每个页面都声明 `#161616` 的 `theme-color` meta。实验室的 Service Worker 在运行期间没有变化；约 08:28 UTC 的一次部署改了一个脚本，此后的读数都记录了加载的是哪个版本（[实验记录](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/2026-10-ios18-baseline.md)，openpwa.net）。

### 读数采集

每一步之后，智能体重启检查器代理，按 URL 与进程选中前台页面，执行一段返回 JSON 的只读表达式。这些表达式没有请求权限、订阅、注册或写入存储，记录推送端点时只取主机名。主屏应用运行在独立于 Safari 的进程中，只有前台页面能读取。WebDriver 自动化窗口只用来读取标签页一侧的值。iOS 会给每个 WebDriver 会话分配隔离的空网站数据存储。截图分析了拍摄时间与像素值，录屏切成了逐帧画面（[REPORT.md](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/REPORT.md)，openpwa.net）。

### 预期与证据等级

测试前，我们把预期写进了为后续 iOS 27 测试准备的检查清单。中途新增步骤时，也先在实验记录里写预期，再读取页面。

结果按证据分级。A 表示仪器读数，S 表示截图或录屏，O 表示只有操作者口述。口述与记录冲突时采用记录，把冲突记为异常；更正另加条目，保留原记录。实验记录条目编号为 N01 至 N66（[实验记录](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/2026-10-ios18-baseline.md)，openpwa.net）。

## 结果

数值旁附有实验记录条目号，A 类结果的原始读数保存在数据包里（[数据包](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/)，openpwa.net）。

### 哪些项目以应用打开

没有 manifest 也没有图标的探测页面，从它自己的主屏图标启动后，在 Safari 的进程里以标签页的视口大小加载，`navigator.standalone` 为 `false`，匹配 `display-mode: browser`，读到的是 Safari 的 localStorage 值，控制页面的是 Safari 的 Service Worker（A，N23）。截图里能看到 Safari 的地址栏和工具栏（S，N63）。manifest 设置了 `display: standalone` 的演示应用以独立模式打开，只匹配 `display-mode: standalone`（A、S；N13）。这确认了 WebKit 16.4 文章中 26 之前的规则。带 manifest 页面弹出的添加面板已截图记录，标题为「添加到主屏幕」，内容包括可编辑名称、URL 和「取消」「添加」两个按钮，没有「Open as Web App」开关（S+O，N66），与 WebKit 在 iOS 26 才加入这个开关相符。

| 上下文 | `navigator.standalone` | display-mode | 内部尺寸（CSS px） | 屏幕 |
|---|---|---|---|---|
| Safari 标签页（四个页面） | false | browser | 402 x 678 | 402 x 874 |
| 从图标打开的探测页面 | false | browser | 402 x 678 | 402 x 874 |
| 演示应用 | true | standalone | 402 x 812 | 402 x 874 |
| 实验室应用 | true | standalone | 402 x 812 | 402 x 874 |

<Figure src="/images/device-tests/2026-10-ios18/t1-probe-in-safari.jpg" width={420} height={913} alt="iPhone 截图：从主屏图标打开的 OpenPWA T1 无 manifest 探测页面。页面显示 navigator.standalone 为 false、display-mode standalone 为 false、display-mode browser 为 true，底部可见显示 openpwa.net 的 Safari 地址栏与工具栏。" caption="在 iOS 18.6.2 上从主屏图标打开的无 manifest 探测页面，在带地址栏的 Safari 中运行（N63）。" />

### 图标

同时声明了 apple-touch-icon 与 manifest 图标的实验室应用，显示的是红色的「180 apple-touch」图标。只有 manifest 的应用显示蓝色的「192 manifest any」图标，没有选用它的 512 px 图标或 maskable 图标。探测页面和一个没有图标的参考页面得到的是黑底字母图块（S，N63）。这确认了 Firtman 笔记里 apple-touch-icon 覆盖 manifest 的说法。

<Figure src="/images/device-tests/2026-10-ios18/home-screen-icons.png" width={900} height={716} alt="iPhone 主屏幕局部截图，有五个测试图标：PWA Lab 的红色图块写着 180 apple-touch，Lab no-ATI 的蓝色图块写着 192 manifest any，两个没有图标的页面是黑底字母 T 和 I，OpenPWA 演示应用图标带一个显示 3 的红色角标。其他应用用灰色遮去。" caption="运行结束后的主屏幕：apple-touch-icon 优先，没有它时用 manifest 的 any 图标，没有图标的页面得到字母图块，演示应用显示角标 3（N60、N63）。" />

### 存储与 Cookie

演示应用存于 localStorage 的语言标记，在应用首次启动时不存在，此后在两个方向上都没有传递（每一步读取一侧为 A，另一侧为操作者报告；N13、N16、N17）。实验室标记在 Safari 与两个主屏应用之间对比了三种存储（A；N18 至 N22）：

| 事件（UTC） | localStorage | IndexedDB | Cookie |
|---|---|---|---|
| 07:13:46 Safari 写入 `TAB-07:13:46` | TAB-07:13:46 | TAB-07:13:46 | TAB-07:13:46 |
| 约 07:16 添加两个实验室应用 | | | |
| 07:34:15 实验室应用首次启动 | null | null | TAB-07:13:46 |
| 07:37:40 实验室应用写入 `APP-07:37:40` | APP | APP | APP |
| 07:38:18 Safari 重新载入 | TAB-07:13:46 | TAB-07:13:46 | TAB-07:13:46 |
| 07:45:25 Safari 写入 `TAB-07:45:25` | TAB-07:45:25 | TAB-07:45:25 | TAB-07:45:25 |
| 07:45:32 只有 manifest 的应用首次启动 | null | null | TAB-07:13:46 |

localStorage 与 IndexedDB 没有复制到应用，之后两边的数据也不互通。Cookie 则复制到每个应用一次，此后两边的写入互不影响。每个应用都有自己的 Cookie 存储：只有 manifest 的应用看不到实验室应用的 `APP` Cookie，尽管 Cookie 路径覆盖两者。只有 manifest 的应用拿到了添加时 Safari 中的旧值，首次启动前 7 秒写入的新值没有复制过来，这与在「添加到主屏幕」时复制一致。两次操作只隔了 7 秒，仍可能是在首次启动时复制了 Safari 尚未落盘的旧值，因此复制时机的证据强度定为中等。这在 18.6.2 上确认了 WebKit 对 Safari 17.2 的描述（[WebKit Features in Safari 17.2](https://webkit.org/blog/14787/webkit-features-in-safari-17-2/)，webkit.org）。

### 状态栏区域

使用默认状态栏样式（没有 meta 标签）时，每个应用内变体在 874 px 高的屏幕上内部高度都是 812 CSS px，`env(safe-area-inset-top)` 为 0。加上 `viewport-fit=cover` 后底部安全区变为 34 px，顶部仍为 0；视口依然从屏幕顶部往下 62 px 处开始，所以无论页头是 static、fixed 还是 sticky，页面内容都到不了那条条带（A；N25 至 N29）。

在演示应用、实验室应用与 Safari 标签页的全部 17 张默认样式竖屏截图中，条带在每个采样点上都是 rgb(22, 22, 22)，即 `#161616`，从未出现 `#000000`。时间后面没有模糊效果，也没有内容（S，N62）。在 Safari 标签页中，蓝色页头滚走、页面顶部变白后，条带仍是 `#161616`，可见标签页用 `theme-color` meta 给状态栏区域着色，没有从页面内容取色，与 Safari 15 文章的描述一致（S）。

<Figure src="/images/device-tests/2026-10-ios18/status-bar-strip.png" width={1248} height={212} alt="三张并排的 iPhone 屏幕顶部截图局部。左：已安装应用，固定的蓝色页头从一条显示时间的深色纯色条带下方开始。中：使用 viewport-fit=cover 与安全区内边距页头的已安装应用，同样从这条深色条带下方开始。右：滚动到页面顶部为白色的 Safari 标签页，上方是同样的深色条带。" caption="iOS 18.6.2 默认状态栏样式：已安装应用（fixed 与 safe-area 变体）和页面顶部为白色的 Safari 标签页中，条带都是纯色 #161616（N62）。" />

截图中的每个应用内页面都把 `#161616` 声明了两次，一次是 `theme-color` meta，一次是 manifest 的 `theme_color`，所以主测试分不出条带取的是哪一个。（在 Safari 标签页中截图的探测页面两者都没有声明，它的条带与页面自己的 `#161616` 页头一致。）约 10:56 UTC 的补测用了三个两种颜色互不相同的新主屏应用，加上实验室的红色变体，并在每张截图的条带内采了六个点（S，N64；操作者对四者的描述全部一致，O）：

| 应用或页面 | manifest `theme_color` | 页面 `theme-color` meta | 条带 |
|---|---|---|---|
| M1 | `#d00000` | `#00a050` | `#00a050` |
| M2 | 无 | `#d00000` | `#d00000` |
| M3 | `#00a050` | 无 | `#00a050` |
| 实验室应用内的红色变体 | `#161616` | `#d00000` | `#d00000` |

在 iOS 18.6.2 上，使用默认状态栏样式时，已安装应用的条带在页面有 `theme-color` meta 时取自它，即使与 manifest 不同也是如此；页面没有 meta 时退回 manifest 的 `theme_color`。红色变体说明颜色跟随当前页面变化，添加应用时没有固定这个值（N65）。manifest 规范允许浏览器让 meta 元素覆盖 manifest 颜色，但不作要求，所以这个结果在一个版本上确定了规范留给浏览器的选择（[Web Application Manifest](https://www.w3.org/TR/appmanifest/)，w3.org）。它也更正了操作者早先「红色变体的条带是黑色」的报告，截图与之相反（N65-a）。未测页面不声明两种颜色的情况，也未测用 `media` 限定 meta、深色外观和加载后用脚本修改 meta。

<Figure src="/images/device-tests/2026-10-ios18/status-bar-colour-source.png" width={1248} height={212} alt="三张已安装测试应用的 iPhone 屏幕顶部截图局部。左：应用 M1，显示时间的条带为绿色。中：应用 M2，条带为红色。右：应用 M3，条带为绿色。每条条带下方的页面标题分别是 T4 18c M1、M2、M3: manifest vs meta theme-color。" caption="iOS 18.6.2 上状态栏颜色的来源：M1（manifest 红、meta 绿）显示绿色，M2（只有 meta 红）显示红色，M3（只有 manifest 绿）显示绿色（N64）。" />

在一个单独安装、使用 `apple-mobile-web-app-status-bar-style: black-translucent` 与 `viewport-fit=cover` 的应用中，视口以 402 x 874 占满屏幕，顶部安全区为 62 px，底部为 34 px（A，N55）；操作者报告看到页面的蓝色页头位于白色状态栏文字后面（O）。这确认了 Apple 已归档的参考文档，以及 Firtman 笔记中 `black-translucent` 仍是全屏应用唯一途径的说法。没有分别安装使用 `default` 和 `black` 的应用来测试。

| 页面 | status-bar-style | `viewport-fit` | 内部高度 | 顶部 / 底部安全区 | 条带 |
|---|---|---|---|---|---|
| baseline、fixed、sticky | 无 | 默认 | 812 | 0 / 0 | 纯色，页面 `theme-color`（S） |
| safe-area | 无 | cover | 812 | 0 / 34 | 纯色，页面 `theme-color`（S） |
| black-translucent 应用 | black-translucent | cover | 874 | 62 / 34 | 页面画在状态栏之下（A） |

### 通知权限

Safari 标签页中没有 `Notification` 与 `PushManager`（A）。在实验室应用中，`Notification.permission` 首次启动时为 `default`，操作者点按权限按钮后为 `granted`（A；N18、N32）。08:17:36 UTC 拍下的截图显示了系统提示，标题为「“PWA Lab”想给你发送通知」，按钮为「不允许」与「允许」（S，N58）。一次授权同时把 Service Worker 注册的 `permissionState` 与 `window.pushManager.permissionState` 都变为 `granted`（A）。

Perm Test 此前没有请求过权限，这次测试全程录屏。`requestPermission()` 于 09:27:59.551 UTC 调用，于 09:28:01.620 UTC 兑现，按 `performance.now()` 计为 2068 ms，结果为 `granted`；录屏中提示出现在约 70.6 s 至 72.5 s，与页面时间的偏差在 1 秒以内（A、S；N53、N54、N59）。不等待用户输入的请求会在几毫秒内兑现。这确认了 16.4 中提示必须跟在用户手势之后的规则，并给出了实测的等待时间。

<Figure src="/images/device-tests/2026-10-ios18/permission-prompts.jpg" width={864} height={913} alt="两张并排的 iPhone 截图。左：PWA Lab 通知页面上方的中文系统提示，询问是否允许 PWA Lab 发送通知，按钮为不允许与允许。右：Perm Test 应用录屏中的一帧，状态面板上方是给 Perm Test 的同类提示。" caption="iOS 18.6.2 zh-CN 界面下的系统权限提示：实验室应用（截图，N58）与从未请求过权限的 Perm Test 应用（录屏第 71.5 s 的画面，N59）。" />

### 推送订阅

实验室应用用 Service Worker 成功订阅，端点位于 `web.push.apple.com`，`expirationTime` 为 `null`，`userVisibleOnly` 为 `true`（A、S；N33）。在同一个应用中，`window.pushManager.getSubscription()` 返回 `null`，演示应用也是同样的情形（A，N41）。两个 worker 的作用域都是子路径，分别为 `/lab/` 下的实验室路径与 `/demo/`，都不在站点根目录。WebKit 说根作用域的 worker 与 window 共享订阅；这些结果与该规则在非根作用域情形下的推论一致，根作用域的 worker 没有测试。另外，普通 Safari 标签页中存在带 `subscribe`、`permissionState` 与 `getSubscription` 的 `window.pushManager`，而那里没有 `PushManager` 与 `Notification`（A；N03、N10）。这里只读取了对象是否存在，没有在标签页中调用 `subscribe()`。按前期检索，这是新的细节。

### notificationclick

两种上下文使用同一个 worker 脚本。我们都在 worker 启动后、脚本给 `self.onnotificationclick` 赋值前读取（A；N03、N18、N34）：

| 表达式 | 由 Safari 标签页控制的 worker | 由主屏应用控制的 worker |
|---|---|---|
| `'onnotificationclick' in self` | false | true |
| `typeof self.onnotificationclick` | undefined | object |
| `'onnotificationclose' in self` | false | true |
| `'onpush' in self` | false | true |
| `'onpushsubscriptionchange' in self` | false | true |
| `'Notification' in self` | false | true |
| `'showNotification' in registration` | false | true |
| `'pushManager' in registration` | false | true |
| `typeof clients.openWindow` | function | function |

授权前后，应用一侧的值都一样。按前期检索，这项差异此前没有公开记录，它也解释了 BCD 的记录：采集器检测的属性，在 worker 由标签页控制时并不存在。随后操作者在四种情形下点按了 worker 显示的六条通知；每次点按都从两条处理路径各产生一条记录（A；N35 至 N40）：

| 点按 | 情形 | 监听器记录 | 属性记录 | 导航 |
|---|---|---|---|---|
| 1 | 主屏幕上的横幅 | 08:23:07.007 | 08:23:07.008 | 聚焦已有窗口 |
| 2 | 应用在前台时的横幅 | 08:23:30.533 | 08:23:30.534 | 聚焦已有窗口 |
| 3 | 主屏幕上的横幅 | 08:24:46.071 | 08:24:46.072 | 聚焦已有窗口 |
| 4 | 通知中心 | 08:26:49.588 | 08:26:49.588 | 聚焦已有窗口 |
| 5 | 应用被划掉并重新启动之后 | 08:28:50.048 | 08:28:50.061 | 聚焦已有窗口 |
| 6 | 点按前应用已被划掉 | 08:43:09.236 | 08:43:09.245 | 聚焦已有窗口 |

两条路径在 6 次点按中都触发了，每次 `clients.matchAll()` 都找到一个窗口，`focus()` 都成功；两个处理函数都没有调用 `event.preventDefault()`，也没有出现 `notificationclose` 记录。第 6 次点按发生在划掉应用约 6 秒后，但上次重新启动时加载的页面仍然存活，点按后也成功聚焦（A，N40）。因此「没有窗口、worker 必须调用 `clients.openWindow()`」这条路径从未走到，测试也没有发送真实的推送消息。这确认了 #22959 中开发者的报告，并补充了两种处理函数写法的细节；对 WebKit 268797 号缺陷中「没有存活页面」的情形，这次测试没有给出任何结论。

<Figure src="/images/device-tests/2026-10-ios18/notification-banner.jpg" width={600} height={547} alt="iPhone 截图：来自 PWA Lab 的通知横幅，内容为 OpenPWA lab notification，shown by the worker after 5 s: tap me (T8)，显示在处于前台的实验室应用通知页面上方。" caption="iOS 18.6.2 上，已安装的实验室应用在前台时出现的通知横幅（N63）。" />

### 安装 API 与角标

`navigator.install`、`BeforeInstallPromptEvent`、`onbeforeinstallprompt` 与 `getInstalledRelatedApps` 在标签页和应用中都不存在（A）。演示应用已有通知权限，调用三次设置角标后，图标显示红色的「3」（S，N60）；`clearAppBadge()` 之后角标消失，这一点只有操作者的报告（O）。这确认了 WebKit 为 16.4 宣布的 Badging API 支持（[WebKit Features in Safari 16.4](https://webkit.org/blog/13966/webkit-features-in-safari-16-4/)，webkit.org）。

### 观察者与工具错误

记录揭示了四次观察者错误。操作者报告一个状态栏步骤跳出了应用，但页面历史长度和加载时间显示，操作者根本没有点按链接（N24、N25）。测试前没有定义「状态栏」，颜色报告说的其实是页面的蓝色页头；我们撤回了这些报告，改用像素测量条带（N46、N62）。操作者还报告首次请求没有出现权限提示，自己的截图却拍到了提示（N58）。另一次，记录者把单字回答理解成也涵盖尚未安装的应用（N50）。

工具也出过问题。WebDriver 的存储彼此隔离；检查器页面列表空了十分钟，切换 Web 检查器后才恢复；部署后 HTTP 缓存还保留着旧脚本（[REPORT.md](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/REPORT.md)，openpwa.net）。

## 主屏应用的代码处理

代码处理方式要结合测试条件看：iOS 18.6.2、iPhone 16 Pro，以及这些测试页面。

### 登录与存储

用户添加站点前，Safari 中已有的登录 Cookie 会复制到应用。测试用的第一方 Cookie 由脚本设置，带 `Secure` 和 `SameSite=Lax`，结果就是如此；localStorage 和 IndexedDB 中的令牌则不会复制过去。创建之后两份 Cookie 存储各自变化，所以之后在 Safari 中退出登录不会清掉应用里的副本（退出登录本身没有测试），同一个源的两次安装之间也会各自变化。登录流程可以利用安装时已存在的 Cookie，不应指望其他存储会带过去，还要处理两边逐渐不一致的情况。[存储隔离条目](/zh/reference/storage/home-screen-storage-isolation/)已经按 WebKit 17.2 的来源写明了这一点。

### 通知点按与特性检测

在 18.6.2 上，已安装应用中的 `notificationclick` 处理函数无论用 `addEventListener` 注册还是赋给 `self.onnotificationclick` 都会运行，并且能聚焦已有窗口。在标签页里做特性检测看不到这一点：由标签页控制的 worker 没有 `onnotificationclick`、没有 `Notification`，也没有 `showNotification`。想描述这个事件的兼容性记录需要注明上下文，BCD 对 `push_event` 就已经这样做了。代码不应根据在已安装应用之外求值的 `'onnotificationclick' in self` 来决定是否注册点按处理函数。

### 推送订阅检查

Service Worker 作用域为子路径的应用，如果通过注册订阅、之后又去问 `window.pushManager.getSubscription()`，会得到 `null`，并可能误以为自己没有订阅。查询建立订阅时用的那个管理器。由于在没有 `PushManager` 与 `Notification` 的 Safari 标签页里也存在 `window.pushManager`，`'pushManager' in window` 不能用来判断「这里能用推送」。

### 屏幕顶部

使用默认样式时，在这个版本上无法把内容放到状态栏后面：布局视口从状态栏下方开始，单靠 `viewport-fit=cover` 只会把底边延伸出去。想让页头颜色出现在时间后面，需要 `apple-mobile-web-app-status-bar-style: black-translucent` 配合 `viewport-fit=cover`，代价是白色状态栏文字会压在页面放在那里的任何内容上。测试页没有用 `env(safe-area-inset-top)` 留内边距，页头照样位于时间后面；想让内容避开时间，就按 62 px 的安全区留出内边距。条带颜色本身由页面决定：在这个版本上，当前页面的 `theme-color` meta 优先于 manifest 的 `theme_color`，后者只在页面没有 meta 时生效，所以页面声明自己的颜色就能改变条带。

## 局限

这些结果描述的是 22G100 版本上的一台 iPhone 16 Pro；iPadOS、其他机型与其他版本都没有测试，而这台手机之后会升级。设备没有抹掉重置，一个身份不明的 Safari Web 扩展运行在 Safari 的进程中，可能影响标签页一侧的读数。white-top、绿色背景、动态变体和深色外观下的条带颜色只有操作者口述，`black-translucent` 应用中时间后面的画面和清除角标也一样；这些结果标为 O，不用于结论。颜色来源补测依据截图和操作员报告，没有对这些应用做仪器读数。我们靠第二份记录发现观察者错误；缺少第二份记录的步骤可能也有同类错误，只是还没发现。读数会在页面中运行 JavaScript，并添加一个隐藏元素和一个临时属性，而且只能读取前台页面。条带颜色来自截图，截图流程没有用实测显示器校验过。只测试了一个由脚本设置的第一方 Cookie；服务端设置的、`HttpOnly`、会话、分区与第三方 Cookie 都没有测试。由于运行中加入了用来区分假设的步骤，实际用了约三个小时，而计划是 60 分钟；每个新增步骤的预期都在读数之前写下（[实验记录](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/2026-10-ios18-baseline.md)，openpwa.net）。

## 下一次运行

这台手机升级到 iOS 27 后，我们会复查同一批页面，包括在 18.6.2 上安装的应用，以便逐项对照。颜色来源测试会增加仪器读数，还会加一个两种颜色都不声明的页面。

Cookie 复制时机会单独测：添加应用后让 Safari 写入新值，至少等两分钟再首次启动应用。测试 `notificationclick` 时，先用读数确认没有存活窗口，再点按通知，让 `clients.openWindow()` 路径运行。

## 站内相关条目

- [iOS 上主屏 Web 应用的存储隔离](/zh/reference/storage/home-screen-storage-isolation/)： WebKit 对已安装应用中存储与 Cookie 的记载。
- [iOS Safari 上的 Web Push](/zh/reference/notifications/ios-safari-push/)：主屏 Web 应用的权限、订阅与投递规则。
- [iOS 添加到主屏幕](/zh/reference/installation/ios-add-to-home-screen/)：保存的站点如何成为 Web 应用或书签。
- [theme_color 与 background_color](/zh/reference/manifest/theme-background-color/)： manifest 颜色成员与 `theme-color` meta 元素。
- [Badging API](/zh/reference/installation/badging/)： `setAppBadge()` 与 `clearAppBadge()`。
- [按版本看 iOS 上的 PWA](/zh/reference/platforms/ios-by-version/)：每个 iOS 版本的有日期记录。

## 待核实

- 既不声明 `theme-color` meta、也不声明 manifest `theme_color` 的页面，默认状态栏条带显示什么，以及带 `media` 限定的 meta 或由脚本修改的 meta 是否生效，都没有测试。
- 在 18.6.2 上，作用域为站点根目录的 Service Worker 是否与 `window.pushManager` 共享订阅，没有测试。
- 在暴露了 `window.pushManager` 的 Safari 标签页中，`window.pushManager.subscribe()` 能否工作，没有测试。
- 应用没有任何存活页面时，`notificationclick` 是否触发、`clients.openWindow()` 是否成功，这条路径没有走到；测试也没有发送真实的推送消息。
- Cookie 是在「添加到主屏幕」时还是在首次启动时复制，强度定为中等：Safari 最后一次写入与第二个应用首次启动之间只隔了 7 秒。
- 服务端设置的、`HttpOnly`、会话、分区与第三方 Cookie 都没有测试。
- `default` 与 `black` 状态栏样式和深色外观都没有仪器读数支持；已安装应用的横屏只有一次仪器读数记录了视口（874 x 402 中占 750 x 402），没有记录是否显示状态栏以及两侧条带的颜色。

## 数据可得性

[数据包](/zh/research/2026-10-ios18-home-screen-web-apps/data/)包括实验记录（N01 至 N66）、测试报告、测试规程、77 个原始 JSON 文件（43 个读数与 34 个元数据附属文件）、带运行时所记哈希的探测脚本、28 张截图（5 张做了遮挡）以及剪辑过的录屏与关键帧，每个文件都有 SHA-256 校验和，另有一个打包文件，以 CC BY 4.0 发布。推送端点只记录了主机名；README 列出了为发布所做的每一处改动。引用时写作「OpenPWA device test, 2026-10-20, iPhone 16 Pro, iOS 18.6.2 (22G100)」，引用单个发现时加上实验记录条目号。演示应用在 [/demo/](/demo/) 上线运行；实验室页面位于 `/lab/` 下，不收录。

## 参考来源

- [OpenPWA device test data, iOS 18.6.2](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/)（openpwa.net）
- [Test report, REPORT.md](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/REPORT.md)（openpwa.net）
- [Headline findings, FINDINGS.md](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/FINDINGS.md)（openpwa.net）
- [Lab notebook, N01 to N66](https://openpwa.net/research/2026-10-ios18-home-screen-web-apps/data/2026-10-ios18-baseline.md)（openpwa.net）
- [iOS PWA Compatibility](https://firt.dev/notes/pwa-ios/)（firt.dev）
- [Web Push for Web Apps on iOS and iPadOS](https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/)（webkit.org）
- [WebKit Features in Safari 16.4](https://webkit.org/blog/13966/webkit-features-in-safari-16-4/)（webkit.org）
- [WebKit Features in Safari 17.2](https://webkit.org/blog/14787/webkit-features-in-safari-17-2/)（webkit.org）
- [Meet Declarative Web Push](https://webkit.org/blog/16535/meet-declarative-web-push/)（webkit.org）
- [WebKit Features in Safari 18.4](https://webkit.org/blog/16574/webkit-features-in-safari-18-4/)（webkit.org）
- [WebKit Features in Safari 26.0](https://webkit.org/blog/17333/webkit-features-in-safari-26-0/)（webkit.org）
- [New WebKit Features in Safari 15](https://webkit.org/blog/11989/new-webkit-features-in-safari-15/)（webkit.org）
- [Tracking Prevention in WebKit](https://webkit.org/tracking-prevention/)（webkit.org）
- [Bug 181849: "Add to homescreen" apps don't share storage with Safari](https://bugs.webkit.org/show_bug.cgi?id=181849)（bugs.webkit.org）
- [Bug 268797: notificationclick events in serviceworkers not firing](https://bugs.webkit.org/show_bug.cgi?id=268797)（bugs.webkit.org）
- [mdn/browser-compat-data#22959](https://github.com/mdn/browser-compat-data/issues/22959)（github.com）
- [browser-compat-data: api/ServiceWorkerGlobalScope.json](https://github.com/mdn/browser-compat-data/blob/main/api/ServiceWorkerGlobalScope.json)（github.com）
- [browser-compat-data: api/Window.json](https://github.com/mdn/browser-compat-data/blob/main/api/Window.json)（github.com）
- [Supported Meta Tags](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html)（developer.apple.com）
- [Configuring Web Applications](https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html)（developer.apple.com）
- [Web Application Manifest](https://www.w3.org/TR/appmanifest/)（w3.org）
- [So what's up with the iOS27 blur?](https://modernwebweekly.substack.com/p/so-whats-up-with-the-ios27-blur)（modernwebweekly.substack.com）
- [ios-webkit-debug-proxy](https://github.com/google/ios-webkit-debug-proxy)（github.com）