# iOS 标签页与主屏应用中的 Service Worker 事件处理器

> iOS 18.6.2 上，'onnotificationclick' in self 在由主屏应用控制的 worker 中为 true，由 Safari 标签页控制时为 false。

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="worker-event-handler-exposure-tab-vs-app" locale="zh" />

同一个 Service Worker 脚本，在 iOS 的 Safari 标签页和主屏应用中暴露的通知、推送成员不同。2026-10-20，我们在 iPhone 16 Pro、iOS 18.6.2（22G100）上读取 `'onnotificationclick' in self`，标签页一侧为 false，应用一侧为 true。这正是 browser-compat-data（BCD）检测 `notificationclick` 的表达式。

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

在 iOS 上，Service Worker 由 Safari 标签页控制时，和由主屏 Web 应用控制时，是否都暴露 `onnotificationclick`、`onpush`、`Notification`，以及注册对象上的 `showNotification` 与 `pushManager`？

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

## 两种环境中的 worker 探测

同一个 worker 脚本 `lab-sw-v2`（`/lab/device-tests/sw.js`，作用域 `/lab/device-tests/`）在两种上下文中读取：

- 在 Safari 中，用 WebDriver 自动化窗口打开 `/lab/device-tests/`，页面注册了 worker 并受其控制（实验记录 N03）。自动化窗口有自己的空网站数据存储；特性检测与存储的数据无关。
- 把同一页面添加到主屏幕，名为「PWA Lab」，再从图标打开。授予通知权限前读一次（N18），授予权限并建立推送订阅后再读一次（N34）。

页面给 worker 发一条探测消息，再把回复打印出来。按线上的 worker 脚本（[sw.js](https://openpwa.net/lab/device-tests/sw.js)），回复分两部分：

- 在 worker 脚本首次运行、尚未给 `self.onnotificationclick` 赋值时读取一次（避免赋值操作自己创建要检测的属性）：`'onnotificationclick' in self`、`typeof self.onnotificationclick`、`'onnotificationclose' in self`、`'onpush' in self` 和 `'onpushsubscriptionchange' in self`；
- 收到探测消息时读取：`'Notification' in self`、`'showNotification' in registration`、`'pushManager' in registration` 和 `typeof clients.openWindow`。

## 怎么运行

标签页和应用两侧用的是同一个页面，不需要 Web 检查器。

1. 在 iPhone 的 Safari 中打开 `https://openpwa.net/lab/device-tests/`，等上下文一行显示有 Service Worker 在控制页面。
2. 在「T7 and T8: notifications」一节点按 **Probe worker exposure**，记下打印出的每个值。
3. 点按分享，选**添加到主屏幕**，再点**添加**。从图标打开 **PWA Lab**。
4. 再次点按 **Probe worker exposure**，比较两组值。
5. 可选：点按 **1. Request permission** 并允许，再探测一次，看权限是否改变应用一侧的值。
6. 在两种上下文中各点按一次 **Copy results as JSON**，把值连同时间和用户代理字符串一起保存；JSON 里的用户代理字符串带有系统版本，但没有单独的版本字段，也没有构建号，构建号需要另外到「设置 > 通用 > 关于本机」记下。

<LabHarnessLinks behaviour="worker-event-handler-exposure-tab-vs-app" locale="zh" />

## 结果

在 iOS 18.6.2（22G100）上，表中的通知与推送成员，在 worker 由 Safari 标签页控制时都不存在，由主屏应用控制时都存在（仪器读数，A；实验记录 N03、N18、N34）。在应用中，授予权限之前这些成员就已存在（N18），授权后的探测返回相同的值（N34），可见这些成员的暴露不需要先授权。

| 表达式 | 由 Safari 标签页控制的 worker（N03） | 由主屏应用控制的 worker（N18、N34） |
|---|---|---|
| `'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 |

在应用上下文中，`notificationclick` 处理函数在 6 次点按中全部运行，见 [iOS 主屏 Web 应用中的 notificationclick 事件](/zh/lab/behaviour/notificationclick-in-home-screen-apps/)。

<LabResults behaviour="worker-event-handler-exposure-tab-vs-app" locale="zh" />

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

## BCD 检测与 WebKit 接口暴露规则

BCD 把 `api.ServiceWorkerGlobalScope.notificationclick_event` 的 `safari_ios` 记为 `version_added: false`（[ServiceWorkerGlobalScope.json](https://raw.githubusercontent.com/mdn/browser-compat-data/main/api/ServiceWorkerGlobalScope.json)，github.com，2026-10-20 读取）。在 [mdn/browser-compat-data#22959](https://github.com/mdn/browser-compat-data/issues/22959)（github.com）中，一位 BCD 贡献者说明：采集器在 Service Worker 中求值 `"onnotificationclick" in self` 来检测这一特性，该检查在 iOS 16、17、18 的 Safari 上都失败，而这个属性受一个 WebKit 偏好设置控制。本次测量给这条记录**补充条件**：worker 由 Safari 标签页控制时检查为 false，由主屏应用控制时为 true。如果采集器是在浏览器标签页中运行检查，这就能解释它得到的 false；该 issue 没有说明采集器用的是哪种上下文。

WebKit 的 iOS 16.4 文章把 Web Push 与通知限定在添加到主屏幕的 Web 应用（[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），同一个 BCD 文件也给 `push_event` 加了备注「Notifications are supported in web apps saved to the home screen」。两者都没有说 worker 自身的成员会随控制上下文而不同。WebKit 252625 号缺陷「NotificationEvent interface exists but Notification interface does not on iOS 16.4」已解决（[Bug 252625](https://bugs.webkit.org/show_bug.cgi?id=252625)，bugs.webkit.org），说明这个平台上的接口暴露以前就出现过不一致。Notifications API 标准在 `ServiceWorkerGlobalScope` 上定义了 `onnotificationclick` 与 `onnotificationclose`（[Notifications API](https://notifications.spec.whatwg.org/)，whatwg.org），没有附加上下文条件。

前期检索没有找到按控制上下文区分这些成员的公开记录。

## 数据

这些值在研究的[数据包](/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-step12-app-lab.json`（N18），授权后在 `raw/2026-10-20-ios18.6.2-step21-app-lab-exposure.json`（N34）。应用一侧的文件都有一个 `.meta.json` 附带文件，记录 UTC 读取时间、工具哈希和所选页面。机器可读的运行记录在 [/lab/results.json](/lab/results.json) 中，id 为 `worker-event-handler-exposure-tab-vs-app/2026-10-20-ios-18.6.2-22g100`。

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

## 相关参考条目

这一结果支撑 [iOS 与 iPadOS 上的 Web Push](/zh/reference/notifications/ios-safari-push/) 对 BCD `notificationclick` 记录的解释，以及 Web Push 兼容性数据中 iOS 版 Safari 一行的主屏条件。

<LabBacks behaviour="worker-event-handler-exposure-tab-vs-app" locale="zh" />

## 局限

- 一台设备、一个版本、一名操作员、一个测试日：iOS 18.6.2（22G100）的 iPhone 16 Pro，没有抹掉重置。
- 标签页一侧的读数来自 WebDriver 自动化窗口，它有自己的空数据存储。设备上装有一个身份不明的 Safari Web 扩展，运行在 Safari 的进程中，可能影响标签页一侧的读数。
- 标签页和应用各自注册了同一个脚本；这里比较的是上下文，不是同一个 worker 实例。
- 只读取了表中的成员。对四个事件处理器属性的五项检测只在 worker 脚本启动时做一次，所以授权后的探测重复的是那次启动时的值；记录无法说明其间 worker 是否重启过。WebKit 功能标志可能改变这些值，本次运行没有记录设备的功能标志状态。
- iPadOS、macOS 上的 Safari 和其他 iOS 版本都没有测试。同一台设备升级到 iOS 27 后会重新测试。

<LabProvenance locale="zh" />