# Safari 对脚本可写存储的 7 天上限

> WebKit 如何计算没有交互的七个 Safari 使用日、这项上限会删除哪些存储形式，以及主屏幕 Web App 为何另有一套计数器。

智能跟踪防护（ITP）会在用户连续七个 Safari 使用日没有与某站点交互之后，删除该站点全部由脚本写入的存储。计数只看使用 Safari 的天数，不按日历算。主屏幕 Web App 在 Safari 之外运行，使用自己的计数器，所以同一个站点可能在标签页里丢失数据，在已安装应用里却仍然保留。

## 工作原理

这项上限分两步到位，真正波及 PWA 离线数据的是第二步。

### 七天到底在数什么

ITP 2.1 于 2019 年 2 月 21 日随 iOS 12.2 与 Safari 12.1 的测试版公布，将持久化客户端 Cookie 的有效期上限设为七天。这包括所有用 `document.cookie` 创建的持久 Cookie。WebKit 解释，跟踪方已经开始往第一方 Cookie 存储中写入标识符；在第一方上下文运行的跟踪脚本可以相互读写数据。

2020 年 3 月 24 日那篇介绍 iOS 与 iPadOS 13.4、macOS 上 Safari 13.1 中 ITP 的文章，把同一限制扩展到其余由脚本写入的存储，原因是第三方脚本已转向 LocalStorage 这类第一方存储，而后者根本没有过期机制。它对触发条件的措辞很精确：在连续七个 Safari 使用日没有与站点发生用户交互之后，删除该站点全部由脚本写入的存储。不打开 Safari，使用日就不增加；与站点交互则会重置计数。

### 这项上限删除哪些存储

WebKit 列出了受影响的脚本可写存储形式，并排除了若干遗留的网站数据类型：

| 存储形式 | PWA 会失去什么 |
|---|---|
| Indexed DB | 结构化的应用数据，包括离线队列与已同步的记录。 |
| LocalStorage | 放在同步存储里的偏好、特性开关与会话线索。 |
| SessionStorage | 被删除源的按标签页状态。 |
| Media keys | 为加密媒体保存的密钥。 |
| Service Worker 注册与缓存 | 注册本身连同它的 Cache Storage 内容。下一次访问没有既有控制者；只有页面再次调用 `register()` 并创建新注册后，新 Worker 才进入安装阶段。 |

这次清理会影响离线功能。如果应用外壳放在 Cache Storage，记录放在 IndexedDB，两者就会连同 Service Worker 注册一起删除。

### 主屏幕 Web App 为何单独计数

WebKit 在 2020 年那篇文章里同时交代了已安装应用。七天上限的触发条件是连续七个 Safari 使用日没有与站点发生用户交互，而这说的是 Safari 里的情形；添加到主屏幕的 Web App 不属于 Safari，因而有自己的使用天数计数器，该计数与 Web App 的实际使用相符，打开它就会重置计时。WebKit 表示，不预期删除这类 Web App 的第一方数据，并请开发者在遇到这种情况时按严重缺陷上报，因为删除 Web App 中第一方的数据并非智能跟踪防护的本意。

## 平台覆盖范围

七天上限只是存储逐出的一种原因。按 WebKit 2023 年的存储策略，超过总配额、系统存储紧张或用户已有一段时间未与站点交互，都可能触发删除，无需用户或站点发起。最后一种就是 ITP 的清理路径。

默认情况下，所有源都使用尽力而为模式。同一篇文章说明，清理时仍有活动页面，或者存储已切换到持久化模式的源，可能免于逐出。

持久化模式可以从脚本申请。该文章说明，源可以用 `StorageManager.persisted()` 查询模式、用 `StorageManager.persist()` 请求切换；自 Safari 17.0 以及 iOS 17、iPadOS 17 与 macOS Sonoma 上的 WebKit 应用起，Storage API 获得完整支持；WebKit 依据「站点是否作为主屏幕 Web App 打开」这类启发式规则决定是否授予请求。文章还提到，独立运行的 Web App（iOS 上的主屏幕 Web App，或 macOS 上添加到程序坞的 Web App）与在浏览器应用中打开时拥有相同的源配额与总配额，而 Cookie 与 HTTP 缓存不受这套管辖存储 API 的配额策略约束。

## 示例

Service Worker 注册缺失时可以重新注册；申请持久化存储也可能让源免于逐出，具体条件见 WebKit 的说明。

### 在 Service Worker 注册缺失时恢复

WebKit 说明七天清理包含 Service Worker 注册和缓存。注册缺失并不能说明它为何不存在，因此下面的示例把这种状态作为重新注册并获取引导数据的条件，而不把它当成 ITP 清理发生过的证据。

```js
async function reseedFromServer() {
  const response = await fetch('/api/bootstrap');
  localStorage.setItem('bootstrap', await response.text());
}

async function restoreMissingRegistration() {
  if (!('serviceWorker' in navigator)) {
    return 'unsupported';
  }
  const registration = await navigator.serviceWorker.getRegistration();
  if (!registration) {
    await navigator.serviceWorker.register('/sw.js');
    await reseedFromServer();
    return 'missing-registration-reseeded';
  }
  return 'intact';
}

restoreMissingRegistration().then((state) => console.log('存储状态：', state));
```

该分支处理文档记录的删除机制，但不把注册缺失当作其原因的证据。WebKit 的文章描述的是客户端网站数据删除，而不是服务端账号删除。

### 从已安装的应用申请持久化模式

WebKit 的启发式规则偏向从主屏幕打开的 Web App，因此在应用安装后申请持久化，比首次在标签页访问时申请更合适。函数会返回申请结果，调用后要检查是否获准。

```js
async function ensurePersistentStorage() {
  if (!('storage' in navigator) || !navigator.storage.persist) {
    return false;                          // 没有 Storage API：按会被删除来规划
  }
  if (await navigator.storage.persisted()) {
    return true;
  }
  return navigator.storage.persist();      // 可能解析为 false，两种结果都要处理
}
```

返回 `false` 表示源仍处于尽力而为模式，数据必须能从服务端重建。返回 `true` 也不等于豁免。2023 年那篇文章的措辞是：源的存储处于持久化模式时「可能」被排除在逐出之外，这是一项条件而不是保证；该文讲的是存储策略，并没有对七天清理作出任何承诺，所以上一个示例里的恢复路径无论如何都值得保留。

:::note
WebKit 在介绍 macOS 上 Safari 13.1 与 iOS、iPadOS 13.4 的 ITP 更新时写道："Web applications added to the home screen are not part of Safari and thus have their own counter of days of use."（[Full Third-Party Cookie Blocking and More](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/)，webkit.org）
:::

## 更正（2026-10-20）

本次修订把第一方 Cookie 表述限定为跟踪脚本，不再把 Service Worker 注册缺失视为 ITP 清理的证据，并删除无来源支持的系统设置测试步骤与账号丢失结论。

## 另请参阅

- [Full Third-Party Cookie Blocking and More](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/)（webkit.org）
- [Intelligent Tracking Prevention 2.1](https://webkit.org/blog/8613/intelligent-tracking-prevention-2-1/)（webkit.org）
- [Updates to Storage Policy](https://webkit.org/blog/14403/updates-to-storage-policy/)（webkit.org）
- [Service Workers：`register()`](https://w3c.github.io/ServiceWorker/#navigator-service-worker-register)（W3C）
- [逐出与尽力而为存储](/zh/reference/storage/eviction/)
- [StorageManager.persist() 与 persisted()](/zh/reference/storage/persistence/)
- [iOS 添加到主屏幕](/zh/reference/installation/ios-add-to-home-screen/)