WWDC Quick Look 💓 By SwiftGGTeam
Explore Safari Web Extension improvements

Explore Safari Web Extension improvements

观看原视频

Highlight

Safari 15 为 Web Extensions 带来了三项关键改进:非持久化后台页面(non-persistent background pages)减少内存占用,declarativeNetRequest API 实现高性能内容拦截,以及新标签页自定义能力。iOS 和 iPadOS 首次支持 Web Extensions。

核心内容

浏览器扩展开发者长期面临一个性能问题:后台页面一旦开启就永远运行,即使用户几小时不用这个扩展,它仍在消耗内存和 CPU。

Safari 15 通过非持久化后台页面解决了这个问题。后台页面只在需要时加载,处理完事件后自动卸载。这对 iOS 设备尤其重要——资源受限的移动设备无法承受多个常驻后台进程。

非持久化后台页面

传统扩展的后台页面是持久的:

{
  "background": {
    "scripts": ["background.js"]
  }
}

这会导致后台进程永远运行。改为非持久化:

{
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  }
}

03:22

关键点:

  • 事件监听器必须在脚本顶层注册,不能在回调内部注册
  • browser.storage API 代替全局变量保存状态
  • 移除 webRequest 监听器,它的事件频率太高,与非持久化页面不兼容
  • browser.alarms 代替 setTimeout/setInterval

使用 storage API 保存状态

// background.js

// 错误:全局变量会在页面卸载后丢失
let replacementCount = 0;

// 正确:使用 storage API
let replacementCount = 0;

browser.storage.local.get('count').then(result => {
    replacementCount = result.count || 0;
});

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.action === 'replace') {
        replacementCount += message.count;
        browser.storage.local.set({ count: replacementCount });
    } else if (message.action === 'getCount') {
        sendResponse({ count: replacementCount });
    }
});

06:55

关键点:

  • browser.storage.local 是异步 API,数据持久化到磁盘
  • 需要在 manifest 中添加 storage 权限
  • 事件监听器注册在 storage.get() 的回调外面,确保页面加载时就注册好

declarativeNetRequest 内容拦截

这是 Chrome 引入的 API,Safari 15 开始支持。规则以 JSON 格式声明,浏览器在底层匹配,扩展不需要运行 JavaScript 就能看到请求内容。

manifest.json:

{
  "permissions": ["declarativeNetRequest"],
  "declarative_net_request": {
    "rule_resources": [
      {
        "id": "ruleset_1",
        "enabled": true,
        "path": "rules.json"
      }
    ]
  }
}

08:37

rules.json:

[
  {
    "id": 1,
    "priority": 1,
    "action": {
      "type": "block"
    },
    "condition": {
      "regexFilter": ".*\\.(jpg|png|gif)$",
      "resourceTypes": ["image"]
    }
  },
  {
    "id": 2,
    "priority": 2,
    "action": {
      "type": "allow"
    },
    "condition": {
      "urlFilter": "||wikipedia.org",
      "resourceTypes": ["image"]
    }
  }
]

09:49

关键点:

  • priority 决定规则应用顺序,数值大的优先
  • action.type 可以是 blockallowupgradeScheme
  • resourceTypes 包括 main_framescriptimagestylesheet
  • domainType 可区分 first-party 和 third-party 请求
  • 扩展不需要 webRequest 权限即可拦截内容,隐私性更好

自定义新标签页

扩展可以接管 Safari 的新标签页:

{
  "chrome_url_overrides": {
    "newtab": "newtab.html"
  }
}

13:34

newtab.html:

<!DOCTYPE html>
<html>
<head>
    <title>My New Tab</title>
    <meta name="theme-color" content="#ff6b6b">
</head>
<body>
    <h1>Welcome!</h1>
    <p>Fun fact of the day...</p>
</body>
</html>

用户开启扩展时,Safari 会询问是否允许扩展接管新标签页。可以在 Safari 设置中随时更改这个选择。

详细内容

调试非持久化后台页面

Safari 的 Develop 菜单中新增了 “Web Extension Background Pages” 选项,可以查看后台页面的加载状态。

// 检查后台页面是否已加载
browser.runtime.getBackgroundPage().then(page => {
    if (page) {
        console.log("Background page is active");
    } else {
        console.log("Background page is unloaded");
    }
});

关键点:

  • getBackgroundPage() 在页面已卸载时返回 null,不会自动唤醒页面
  • 要唤醒后台页面,发送一条消息即可
  • 在 Develop 菜单中点击后台页面会立即加载它

iOS 上的特殊注意事项

iOS 扩展必须使用非持久化后台页面。manifest 中如果省略 persistent 字段,默认就是 true,在 iOS 上会导致扩展无法加载。

{
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "permissions": ["storage", "declarativeNetRequest"]
}

规则集动态更新

// 启用或禁用特定规则集
browser.declarativeNetRequest.updateEnabledRulesets({
    disableRulesetIds: ['ruleset_1'],
    enableRulesetIds: ['ruleset_2']
});

// 获取当前规则集状态
browser.declarativeNetRequest.getEnabledRulesets().then(ids => {
    console.log("Enabled rulesets:", ids);
});

核心启发

1. 为 iOS 开发广告/内容拦截扩展

用 declarativeNetRequest API 构建轻量级拦截器,规则文件可以远程更新,无需提交 App Store 审核。入口 API:declarativeNetRequest + updateEnabledRulesets()

2. 创建跨平台的密码管理器扩展

用非持久化后台页面 + storage API 保存用户凭证,通过 content script 在网页表单中自动填充。入口 API:browser.storage.local + content_scripts

3. 开发 productivity 类新标签页扩展

接管 Safari 新标签页,展示待办事项、天气或每日一句。用 theme-color meta 标签让标签栏颜色与扩展风格统一。入口 API:chrome_url_overrides + newtab

4. 构建开发者工具扩展

在网页上注入 content script,展示元素的布局信息、颜色值或性能数据。用 browser.runtime.sendMessage 与后台页面通信聚合数据。入口 API:content_scripts + browser.runtime.onMessage

5. 实现网页暗黑模式强制切换

用 content script 检测网页当前主题,通过 declarativeNetRequest 拦截并修改 CSS 文件请求,或直接用 JavaScript 注入反转颜色的样式。入口 API:content_scripts + CSS 注入。

关联 Session

评论

GitHub Issues · utterances