# macOS 上的 Safari PWA（Dock 应用）

> macOS Sonoma 与 Safari 17 起，网站如何通过 Safari 的 Add to Dock 安装为 Dock 应用，manifest 控制什么，以及 Dock 应用与 iOS 有何差异。

自 macOS Sonoma（14）配合 Safari 17（2023-09）起，Safari 中打开的任何网站都可以作为 Web 应用添加到 Dock。它随后在自己的窗口中启动，工具栏精简，拥有独立的 Cookie 和网站数据，并且可以使用 Service Worker、Web Push、通知和角标；Web 应用 manifest 决定这个 Dock 应用的名称和显示方式。

## 工作原理

Safari 从当前打开的页面创建 Web 应用；manifest 可选，存在时会被使用。启动流程的是用户，不是网站。

### Add to Dock

Apple 支持文章 [Use Safari web apps on Mac](https://support.apple.com/en-us/104996)（需要 macOS Sonoma 14 或更高版本）给出路径（英文界面）：打开网站后，在菜单栏选择 **File > Add to Dock**，或点按 **Share** 按钮并选择 **Add to Dock**；按需修改名称，点按 **Add**。应用被写入用户个人文件夹内的 Applications 文件夹，可从 Dock、启动台或聚焦搜索启动。移除它的方式是在访达中通过 **Go > Home > Applications** 把该应用拖到废纸篓。

### manifest 控制什么

存在 manifest 时，Safari 17 读取 `display`、`name`、`theme_color` 和 `start_url` 来塑造应用，见 [Safari 17.0 功能说明](https://webkit.org/blog/14445/webkit-features-in-safari-17-0/)。没有 manifest 时，Safari 从页面标题推导名称、从网站推导图标，窗口仍然以 Web 应用方式打开。用户之后可以在应用自己的设置窗口中覆盖这两项，该窗口还提供 **Show navigation controls**（前进、后退、共享和扩展按钮）与 **Show color in title bar** 两个选项。

### 数据、Cookie 与扩展

创建时 Safari 会把网站的 Cookie 复制到新应用中，因此基于 Cookie 的登录状态得以延续；其他存储一律不复制，此后该应用不再与 Safari 共享任何历史记录、Cookie、网站数据或设置，类似一个独立的 Safari 描述文件。Safari 扩展可以在各 Web 应用的设置中单独开启。Dock 应用中的每个源享有 WebKit 的浏览器应用配额（macOS 14 及之后约为磁盘的 60%），并遵守与 Safari 相同的尽力而为淘汰规则。

### 通知、推送与角标

Dock 应用可以使用 Web Push、Notifications API、Service Worker 和 Badging API。只有在 Web 应用内部（而非 Safari 中）授予的通知权限才会启用 Dock 图标上的红色未读角标，应用会以自己的名称出现在 **System Settings > Notifications** 中。通过 `window.pushManager` 订阅、无需 Service Worker 的声明式 Web Push，随 macOS 15.5 登陆 Mac，见 [WebKit 公告](https://webkit.org/blog/16535/meet-declarative-web-push/)。

## 示例

Dock 应用和 Safari 标签页运行同一份代码，所以下面每项能力都要探测，不能假设。

### 只在 API 存在且应用已安装时设置角标

`setAppBadge()` 在 Dock 应用中存在、在 Safari 标签页中不存在；在通知尚未被允许时设置的计数会被存储并在之后显示。

```js
async function updateUnreadBadge(count) {
  const standalone =
    typeof window.matchMedia === 'function' &&
    window.matchMedia('(display-mode: standalone)').matches;

  if (!standalone || typeof navigator.setAppBadge !== 'function') {
    // Safari 标签页，或没有 Badging 的引擎：把计数放进页面标题。
    document.title = count > 0 ? `(${count}) 收件箱` : '收件箱';
    return;
  }
  if (count > 0) {
    await navigator.setAppBadge(count);
  } else {
    await navigator.clearAppBadge();
  }
}
```

即使在应用内部也要保留页面标题的回退：拒绝了通知的用户看不到 Dock 角标，窗口标题是下一个最显眼的位置。

### 向 macOS 访客指出 File > Add to Dock

Safari 没有安装事件，提示是网站自己的事，而且只应出现在 macOS 14 及之后的 Safari 标签页中。

```js
const isMacSafariTab =
  /Macintosh/.test(navigator.userAgent) &&
  /Safari\//.test(navigator.userAgent) &&
  !/Chrome\//.test(navigator.userAgent) &&
  window.matchMedia('(display-mode: browser)').matches;

if (isMacSafariTab) {
  showHint('把本站添加到 Dock：File > Add to Dock');
} else {
  hideHint();
}
```

User-Agent 嗅探分不出 Sonoma 和更早的 macOS，所以提示的措辞要做到菜单项不存在时也无害。

## 实测行为

Web 应用的设置窗口既是覆盖 manifest 选择的地方，也是两个工具栏开关所在的位置。

:::observed
macOS Sonoma 14 上的 Safari Web 应用（英文界面）：点按菜单栏中的应用名称并选择 **Settings**，会打开一个包含 "Application Name"、"Application URL"（带 "Set to Current Page" 按钮）、"Icon" 字段以及 "Show navigation controls"、"Show color in title bar" 两个复选框的面板，另有 "Privacy" 与 "Extensions" 标签页。见 Apple 的 [Use Safari web apps on Mac](https://support.apple.com/en-us/104996)。
:::

没有书签和标签页是有意为之：工具栏只提供后退、前进、共享和扩展按钮，**Share > Open in Safari** 可以把页面交还给浏览器。

## 另请参阅

- [iOS 与 Safari 上的 PWA](/zh/reference/platforms/ios-safari/)
- [桌面安装](/zh/reference/installation/desktop-install/)
- [角标](/zh/reference/installation/badging/)
- [Web Push](/zh/reference/notifications/web-push/)
- [Use Safari web apps on Mac](https://support.apple.com/en-us/104996)（support.apple.com）
- [WebKit Features in Safari 17.0](https://webkit.org/blog/14445/webkit-features-in-safari-17-0/)（webkit.org）
- [Meet Declarative Web Push](https://webkit.org/blog/16535/meet-declarative-web-push/)（webkit.org）