# iOS 上的 Declarative Web Push 订阅范围

> iOS 18.6.2 上，子路径作用域的 worker 已有订阅时，window.pushManager.getSubscription() 仍返回 null；普通 Safari 标签页中也有这个管理器。

import LabEvidenceLine from '@components/lab/LabEvidenceLine.astro';
import LabHarnessLinks from '@components/lab/LabHarnessLinks.astro';
import LabResults from '@components/lab/LabResults.astro';
import LabBacks from '@components/lab/LabBacks.astro';
import LabProvenance from '@components/lab/LabProvenance.astro';

<LabEvidenceLine behaviour="declarative-web-push-subscription-scope" locale="zh" />

从 iOS 18.4 起，页面可以用 `window.pushManager`（Declarative Web Push）或 Service Worker 注册对象订阅推送。2026-10-20 的实测中，iPhone 16 Pro、iOS 18.6.2（22G100）的 Safari 标签页里也有 `window.pushManager`；在主屏应用里，它没有返回子路径 worker 的订阅。

<span id="问题"></span>

在 iOS 上，主屏 Web 应用的 Service Worker 作用域为子路径、并通过注册建立订阅时，`window.pushManager.getSubscription()` 会不会返回这份订阅？还需要确认一次授权能否同时覆盖两个管理器，以及普通 Safari 标签页中是否暴露 `window.pushManager`。

<span id="测了什么"></span>

## 两个订阅管理器

我们测试了两个主屏应用，worker 都以子路径为作用域，分别是真机实验室的测试工具「PWA Lab」（作用域 `/lab/device-tests/`）和 OpenPWA 演示应用（作用域 `/demo/`）。订阅由两个应用各自调用 `registration.pushManager.subscribe()` 建立。调用时传入 `userVisibleOnly: true` 和应用服务器公钥。只保留 endpoint 主机名。其余读数项目如下。

- `registration.pushManager.getSubscription()`：endpoint 主机、endpoint 路径长度、`expirationTime`、`options.userVisibleOnly`，以及 `applicationServerKey` 是否一致；
- `window.pushManager.getSubscription()`；
- 两个管理器上的 `permissionState({userVisibleOnly: true})`，授权前后各一次。

在 Safari 标签页中只读取暴露情况：`'pushManager' in window`、它的 `subscribe`、`permissionState` 与 `getSubscription` 成员的类型、`'PushManager' in window` 以及 `'Notification' in window`。任何上下文中都没有调用 `window.pushManager.subscribe()`，也没有测试根作用域的 worker。

## 怎么运行

第 4、5 步需要 Web 检查器。在 iPhone 上打开 Safari 高级设置中的 Web 检查器（英文界面为 Settings → Apps → Safari → Advanced → Web Inspector），在 Mac 上从 Safari 的 Develop 菜单选择这台 iPhone 和应用页面。

1. 在 iPhone 的 Safari 中打开 `https://openpwa.net/lab/device-tests/`，查看 Results panel（T5, T9, T10）：它打印 `'pushManager' in window`、`window.pushManager.subscribe` 与 `permissionState` 的类型、`'PushManager' in window` 和 `'Notification' in window`。
2. 把页面添加到主屏幕（分享、**添加到主屏幕**、**添加**），打开 **PWA Lab**。
3. 点按 **1. Request permission** 并允许，再点按 **Subscribe to push**。结果一行会显示 endpoint 主机。
4. 在 Web 检查器控制台中求值 `(await navigator.serviceWorker.getRegistration()).pushManager.getSubscription()` 和 `await window.pushManager.getSubscription()`。只记 endpoint 主机，不要记完整的 endpoint 或密钥。
5. 求值 `await window.pushManager.permissionState({userVisibleOnly: true})`，并在注册的 `pushManager` 上做同样的调用。

<LabHarnessLinks behaviour="declarative-web-push-subscription-scope" locale="zh" />

## 结果

在 iOS 18.6.2（22G100）的 PWA Lab 应用中，注册上的订阅 endpoint 位于 `web.push.apple.com`，路径长度 172，`expirationTime` 为 null，`userVisibleOnly` 为 true，公钥与测试工具一致；与此同时 `window.pushManager.getSubscription()` 返回 null（仪器读数，A；实验记录 N33）。演示应用的情形相同：endpoint 主机 `web.push.apple.com`，`expirationTime` 为 null，`window.pushManager.getSubscription()` 返回 null（A；N41）。在 PWA Lab 和从未请求过权限的 Perm Test 应用中，一次权限授予都把两个管理器的 `permissionState` 同时变为 granted（A；N32、N54）。

在普通 Safari 标签页中，`'pushManager' in window` 为 true，`subscribe`、`permissionState` 和 `getSubscription` 都是函数，而 `'PushManager' in window` 与 `'Notification' in window` 为 false（A；N03、N10）。这里只确认了对象和成员是否存在，没有尝试在标签页中调用 `window.pushManager.subscribe()`。

<LabResults behaviour="declarative-web-push-subscription-scope" locale="zh" />

<span id="文档怎么说"></span>

## 根作用域与主屏应用要求

WebKit 的 [Meet Declarative Web Push](https://webkit.org/blog/16535/meet-declarative-web-push/)（webkit.org）写道，作用域为网站根目录（「scoped to the root level of your website domain」）的已注册 Service Worker 与 window 共享推送订阅。worker 以子路径为作用域时，window 上的管理器没有返回它的订阅，这与 WebKit 的描述一致，补上了规则未覆盖的情形。根作用域的 worker 没有测试，因此不能用这次结果确认或否定规则所说的共享订阅。共享权限这一点，文章没有提到。

WebKit 的 Safari 18.4 文章说 Declarative Web Push「is now available on iOS and iPadOS 18.4 for web apps added to the Home Screen」（[WebKit Features in Safari 18.4](https://webkit.org/blog/16574/webkit-features-in-safari-18-4/)，webkit.org），BCD 把 `api.Window.pushManager` 记为 iOS 版 Safari 18.4 起支持，标为实验性（[Window.json](https://raw.githubusercontent.com/mdn/browser-compat-data/main/api/Window.json)，github.com）。两者都没有说普通标签页中是否存在这个对象。标签页的结果补充了一个条件。在 18.6.2 上，这个对象在没有 `Notification`、也没有 `PushManager` 的标签页中同样暴露，所以 `'pushManager' in window` 并不能说明那里可以使用推送。Push API 通过 `PushManagerAttribute` mixin 定义了 `window.pushManager`，`Window` 在安全上下文中包含这个 mixin（[Push API](https://w3c.github.io/push-api/)，w3.org）；规范没有提到 WebKit 文章所说的主屏条件。

前期检索未见公开记录提到标签页也暴露这个对象；子路径订阅则与 WebKit 已有描述一致，为它补上了实测案例。

## 数据

这些值在研究的[数据包](/zh/research/2026-10-ios18-home-screen-web-apps/data/)中（CC BY 4.0）：标签页一侧在 `raw/2026-10-20-ios18.6.2-tab-lab.json`（N03）和 `raw/2026-10-20-ios18.6.2-step03-tab-demo-push.json`（N10）；PWA Lab 在 `raw/2026-10-20-ios18.6.2-step19-app-lab-perm.json`（N32）和 `raw/2026-10-20-ios18.6.2-step20-app-lab-sub.json`（N33）；演示应用在 `raw/2026-10-20-ios18.6.2-step25b-app-demo-push.json`（N41）；Perm Test 在 `raw/2026-10-20-ios18.6.2-25c-post-app-perm.json`（N54）。没有任何原始文件包含完整的 endpoint。机器可读的运行记录在 [/lab/results.json](/lab/results.json) 中，id 为 `declarative-web-push-subscription-scope/2026-10-20-ios-18.6.2-22g100`。

<span id="支撑的条目"></span>

## 相关参考条目

这一结果支撑 [iOS 与 iPadOS 上的 Web Push](/zh/reference/notifications/ios-safari-push/) 和 [Web Push 与 PushManager.subscribe()](/zh/reference/notifications/web-push/) 中关于 Declarative Web Push 的段落，以及 Web Push 兼容性数据中 Declarative Web Push 一行的条件。

<LabBacks behaviour="declarative-web-push-subscription-scope" locale="zh" />

## 局限

- 一台设备、一个版本、一名操作员、一个测试日：iOS 18.6.2（22G100）的 iPhone 16 Pro。
- 两个 worker 的作用域都是子路径。WebKit 规则所针对的根作用域 worker 没有测试。
- 没有调用 `window.pushManager.subscribe()`，标签页和应用中都没有，所以这里无法说明 window 上的订阅对 worker 是否可见，也无法说明标签页能否订阅。
- 没有投递推送消息，测试工具没有推送服务器。
- 演示应用中的提示只有操作员的口头报告；它的权限状态和订阅是仪器读数。
- iPadOS、macOS 上的 Safari 和其他 iOS 版本都没有测试。同一台设备升级到 iOS 27 后会重新测试。

<LabProvenance locale="zh" />