# iOS 主屏 Web 应用中的 notificationclick 事件

> iOS 18.6.2 上，主屏 Web 应用的 notificationclick 在 6 次点按中全部经由 addEventListener 与 onnotificationclick 两条路径触发。

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="notificationclick-in-home-screen-apps" locale="zh" />

`notificationclick` 在主屏 Web 应用的 6 次通知点按中都触发了，两种处理器都运行成功。测试于 2026-10-20 在 iPhone 16 Pro、iOS 18.6.2（22G100）上完成；browser-compat-data（BCD）却把这个事件记为 iOS 版 Safari 不支持。

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

在 iOS 主屏 Web 应用中，用户点按 Service Worker 自己显示的通知时，`notificationclick` 处理函数是否会运行？用 `addEventListener('notificationclick', …)` 注册和赋给 `self.onnotificationclick` 两种方式是否都有效？处理函数能否把应用窗口切到前台？

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

## 处理器与点按情形

测试应用是从 Safari 添加到主屏幕的真机实验室测试工具（v1），名为「PWA Lab」。它的 Service Worker（`lab-sw-v2`，作用域 `/lab/device-tests/`）装了两个处理函数：一个用 `addEventListener` 注册，一个赋给 `self.onnotificationclick`。两个处理函数各自往 IndexedDB 写入带时间戳的记录，用 `via` 字段区分路径；两者都不调用 `event.preventDefault()`。

跳转只由监听器负责。它先调用 `clients.matchAll({type: "window", includeUncontrolled: true})`，找到实验室窗口就对它调用 `focus()`，找不到才调用 `clients.openWindow()`，结果随记录一起保存。

按钮 2a 由页面立即调用 `registration.showNotification()`；按钮 2b 给 worker 发一条消息，worker 等 5 s 后调用 `self.registration.showNotification()`（见 [lab.js](https://openpwa.net/lab/device-tests/lab.js) 和 [sw.js](https://openpwa.net/lab/device-tests/sw.js)）。第 4 次点按用的是 2a，其余五次用的是 2b。没有发送任何推送消息，测试工具没有推送服务器。应用此前已获得通知权限（实验记录 N32）。

一共跑了五种点按情形，都在主屏应用的上下文中：

- 在主屏幕上点按横幅；
- 应用在前台时点按横幅；
- 在通知中心点按通知；
- 在应用划掉并重新打开之后点按横幅；
- 在多任务界面划掉应用之后点按横幅，试图走到 `clients.openWindow()` 路径。

每条记录有两个时间：`createdAt` 是页面构造通知参数的时间（2b 在 5 s 等待之前），`at` 是处理函数开始构造记录的时间（在跳转和写入 IndexedDB 之前）。监听器记录还保存了 `clients.matchAll()` 返回的窗口数和跳转结果。一个 AI 代理会话通过 USB 经 WebKit 远程检查器从应用页面读取累积的记录，共读了四次，分别在第 3、4、5、6 次点按之后（N35、N36、N38、N40）；每次读数也能看出是否存在 `notificationclose` 记录。

## 怎么运行

需要一台 iPhone，大约十分钟。Web 检查器可以不用，测试页面会自己打印事件日志。

1. 在 iPhone 的 Safari 中打开 `https://openpwa.net/lab/device-tests/`，点按分享，选**添加到主屏幕**，再点**添加**。
2. 从图标打开 **PWA Lab**。在「T7 and T8: notifications」一节点按 **1. Request permission**，在系统提示中选**允许**。
3. 点按 **2b. Show in 5 s (then go Home)**，立即回到主屏幕。横幅出现后点按它。
4. 回到应用查看事件日志。两条路径都触发时，每次点按会新增一条标为 `addEventListener` 的记录和一条标为 `onnotificationclick property` 的记录，监听器记录里写有跳转结果。
5. 点按 **2a. Show notification now**，留在应用中，下拉通知中心，在那里点按这条通知。
6. 在多任务界面关闭应用，再从图标打开，重复第 3 步。
7. 测试无窗口路径：点按 **2b**，立即在多任务界面划掉应用，然后点按横幅。结果为「opened new window」说明 `clients.openWindow()` 运行了；「focused existing window」说明页面仍然存活。
8. 点按 **Copy results as JSON** 保存记录。JSON 里有读取时间（`collectedAt`）和用户代理字符串，但没有设备型号和系统构建号，这两项要到「设置 > 通用 > 关于本机」另外记下。

<LabHarnessLinks behaviour="notificationclick-in-home-screen-apps" locale="zh" />

## 结果

在 iOS 18.6.2（22G100）上，两条处理路径在 6 次点按中全部运行，共产生 12 条记录，每次点按两条（仪器读数，A；实验记录 N35、N36、N38、N40）。每次点按时 `clients.matchAll()` 都返回一个窗口，对它调用 `focus()` 都成功。没有出现 `notificationclose` 记录。应用在前台时也会显示横幅（截图或录屏，S；N63）。

| 点按 | 情形 | `createdAt` | 监听器 `at` | 属性 `at` | 实验记录 |
|---|---|---|---|---|---|
| 1 | 横幅，主屏幕 | 08:22:57.000 | 08:23:07.007 | 08:23:07.008 | N35 |
| 2 | 应用在前台时的横幅 | 08:23:21.253 | 08:23:30.533 | 08:23:30.534 | N35、N63 |
| 3 | 主屏幕上的横幅 | 08:24:38.479 | 08:24:46.071 | 08:24:46.072 | N35、N63 |
| 4 | 通知中心 | 08:26:28.601 | 08:26:49.588 | 08:26:49.588 | N36 |
| 5 | 划掉并重新打开之后 | 08:28:40.822 | 08:28:50.048 | 08:28:50.061 | N38 |
| 6 | 点按前已划掉应用 | 08:43:03.022 | 08:43:09.236 | 08:43:09.245 | N40 |

时间为 2026-10-20 的 UTC。从 `createdAt` 到 `at` 的间隔包含操作员的反应时间，2b 的几次点按（除第 4 次外）还包含 5 s 等待，所以不能当作事件派发延迟。每次点按时都有存活的窗口：第 6 次点按时，操作员大约 6 s 前划掉了应用，但上一次重新打开时加载的文档还在，通知点按把它切到了前台（N40）。因此 `clients.openWindow()` 路径没有走到，这种方法下记为无法运行。

<LabResults behaviour="notificationclick-in-home-screen-apps" 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 读取）。实测与 BCD 不符。在 2024-04-29 提交、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 上都失败。采集器的 worker 由 Safari 标签页控制。在 18.6.2 上，这种上下文里该属性不存在，而且标签页没有 `Notification` 接口，根本显示不了可以点按的通知（见 [worker 事件处理属性的暴露](/zh/lab/behaviour/worker-event-handler-exposure-tab-vs-app/)）。这条记录对它所测的上下文是对的，只是推广到了整个 iOS 版 Safari。同一个 BCD 文件已经给 `push_event` 加了备注「Notifications are supported in web apps saved to the home screen」。同一个 issue 里有参与者报告该事件在 iOS 18 的已安装应用中会触发；本次运行用一份有日期的测量确认了这一报告，不是新发现。

WebKit 268797 号缺陷「notificationclick events in serviceworkers not firing」于 2024-02-05 针对 iOS 17 提交，状态为 NEW，最后修改于 2026-10-12（[Bug 268797](https://bugs.webkit.org/show_bug.cgi?id=268797)，bugs.webkit.org）。其中的报告涉及多种应用状态。评论 35（iOS 18.7）指出，用户点按推送通知时若应用没有存活页面，就会丢失点按事件；评论 40（iOS 26.6.2）描述的是另一种规律。本次运行没有发送推送消息，每次点按时都有窗口存活，所以既不能确认也不能否定这个缺陷。

Notifications API 标准把 `notificationclick` 定义为 Service Worker 事件（[Notifications API](https://notifications.spec.whatwg.org/)，whatwg.org），Service Workers 规范定义了 `clients.openWindow()`（[Service Workers](https://w3c.github.io/ServiceWorker/#clients-openwindow)，w3.org）。MDN 的 [notificationclick 事件](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/notificationclick_event)页面（developer.mozilla.org）给出的也是测试工具所用的写法：先 `matchAll()`，再 `focus()` 或 `openWindow()`。

## 数据

脱敏后的证据在研究的[数据包](/zh/research/2026-10-ios18-home-screen-web-apps/data/)中（CC BY 4.0）。事件记录分别在 `raw/2026-10-20-ios18.6.2-step22-app-lab-events.json`（第 1 至 3 次点按，N35）、`raw/2026-10-20-ios18.6.2-step23-app-lab-events.json`（第 4 次，N36）、`raw/2026-10-20-ios18.6.2-step24-app-lab-events.json`（第 5 次，N38）和 `raw/2026-10-20-ios18.6.2-step24b-app-lab-events.json`（第 6 次，N40），每个文件都有一个 `.meta.json` 附带文件，记录 UTC 读取时间和工具哈希。横幅截图为 `screenshots/2026-10-20_iphone16pro_ios18.6.2_T8_1a.png` 与 `…_T8_1b_redacted.png`。机器可读的运行记录在 [/lab/results.json](/lab/results.json) 中，id 为 `notificationclick-in-home-screen-apps/2026-10-20-ios-18.6.2-22g100`。

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

## 相关参考条目

这一结果支撑 [iOS 与 iPadOS 上的 Web Push](/zh/reference/notifications/ios-safari-push/) 中关于通知点按的一节，以及 `notificationclick` 条目里 iOS 版 Safari 单元格上的实测条件。

<LabBacks behaviour="notificationclick-in-home-screen-apps" locale="zh" />

## 局限

- 一台设备、一个版本、一名操作员、一个测试日：iOS 18.6.2（22G100）的 iPhone 16 Pro，没有抹掉重置，装有其他主屏应用和一个 Safari Web 扩展。
- 只点按了 `registration.showNotification()` 显示的本地通知。没有投递推送消息，因此没有制造出 WebKit 268797 号缺陷中报告的推送条件。
- 每次点按时都有窗口存活。没有走到无窗口存活时的 `clients.openWindow()` 路径。针对这条路径的测试列在[路线图](/zh/lab/roadmap/)上。
- 只有一个子路径作用域的 worker 脚本，没有通知操作按钮，没有调用 `event.preventDefault()`，也没有测试 `notificationclose`。
- iPadOS、其他 iPhone 机型和其他 iOS 版本都没有测试。

<LabProvenance locale="zh" />