Back

Chrome 扩展 Manifest V3 详解

Chrome 扩展 Manifest V3 详解

如果你最近搜索过 Chrome 扩展开发教程,可能会注意到一个令人头疼的问题:你找到的指南中,有一半都引用了一种已经无法工作的 background page 架构。Manifest V2 已被弃用,并在 Chrome 中默认禁用。Manifest V3 才是当前的平台,理解其架构是 2026 年扩展开发唯一切实可行的起点。

本文将解释发生了哪些变化、为何变化,以及关键 API 之间是如何协同工作的。

核心要点

  • Manifest V2 已被弃用;Manifest V3 是新建 Chrome 扩展唯一切实受支持的路径。
  • 持久化后台页面被事件驱动的 service worker 所取代,后者无法访问 DOM,且不应依赖事件之间内存状态的持久性。
  • declarativeNetRequest API 取代了阻塞式的 webRequest,将网络过滤从扩展代码转移到原生规则评估。
  • 所有扩展 JavaScript 必须打包在扩展程序内 —— 远程托管代码被禁止。
  • 统一的 chrome.action API 和 Offscreen API 填补了 MV2 中 browserActionpageAction 以及持久化后台页面留下的空缺。

Chrome 为何放弃 Manifest V2

Manifest V2 扩展可以运行一个持久化的 background page —— 一个完整的 HTML 文档,无限期地驻留在内存中,即使扩展什么也没做也是如此。这对开发者来说很方便,但对用户来说代价高昂。每个安装了带 background page 扩展的用户,都会持续消耗内存和 CPU。

除了性能问题,MV2 还允许扩展从远程 URL 加载并执行 JavaScript。这意味着一个扩展可以在通过 Chrome Web Store 审核时使用无害代码,随后再悄悄从外部服务器换入恶意逻辑。当时几乎没有实际可行的方式来审计扩展实际运行的内容。

这两个问题 —— 资源浪费和无法审计的远程代码 —— 是推动 Manifest V3 诞生的真正原因。

Chrome 扩展 Manifest V3 的核心架构变化

扩展 Service Worker 取代后台页面

在 MV3 中,持久化的 background page 已经消失。取而代之的是 扩展 service worker —— 一个事件驱动的脚本,Chrome 在需要时启动它,在空闲时终止它。

这是让大多数从 MV2 迁移过来的开发者感到困惑的变化。service worker 无法访问 DOM,也不会在事件之间保持存活。你不能把状态存储在全局变量中并期望它持久存在。相反,对于需要跨事件保留的内容,请使用 chrome.storage;对于以前在 background page 中通过 setInterval 实现的定期任务,请使用 chrome.alarms API 来调度。

{
  "background": {
    "service_worker": "background.js",
    "type": "module"
  }
}

declarativeNetRequest 取代阻塞式 webRequest

MV2 的 webRequest API 允许扩展拦截每一个网络请求,并同步决定是否阻止或修改它。这赋予了扩展对所有浏览器流量的广泛可见性 —— 一个重大的隐私暴露 —— 同时也引入了延迟,因为每个请求都必须等待扩展的响应。

declarativeNetRequest API(DNR)的工作方式不同。你以 JSON 形式定义一组规则,Chrome 原生地评估它们,扩展不再需要在 JavaScript 中同步拦截请求来阻止或修改它们。这种设计本身就更快、更注重隐私。

自 Chrome 120 起,规则数量的限制相比 MV3 早期已大幅放宽。像 uBlock Origin Lite 这样的内容拦截器已经发布了兼容 MV3 的版本,所以”MV3 杀死了广告拦截器”的说法并不完全准确 —— 不过,过滤模型确实比 MV2 时代的方法更具限制性,而原版 uBlock Origin 因作者的选择仍然仅支持 MV2。

不再允许远程托管代码

MV3 扩展执行的所有 JavaScript 必须打包在扩展程序内部。不允许从外部 CDN 或 API 加载可执行代码。这使得每个扩展在审核时都能被完整审计。

chrome.action API 与 Offscreen API

MV2 中的 browserActionpageAction API 在 MV3 中被统一为单一的 chrome.action API。它通过一个一致的接口处理工具栏图标、徽章文本和弹出窗口。

对于需要从后台上下文访问 DOM 或播放音频的场景 —— 这些是 service worker 无法完成的 —— MV3 提供了 Offscreen API。它允许你专门为这些任务创建一个极简的、隐藏的文档,而无需承担完整持久化后台页面的开销。根据 Can I Use,相关的 offscreen API 现已在现代 Chromium 内核浏览器中得到广泛支持。

一个最简 MV3 Manifest 的样子

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0",
  "background": { "service_worker": "background.js" },
  "action": { "default_popup": "popup.html" },
  "permissions": ["storage", "activeTab"],
  "host_permissions": ["https://example.com/*"]
}

请注意,host permissions(主机权限)现在与 API 权限分开声明 —— 这是一个有意的改动,使用户能更清楚地了解扩展可以访问哪些站点。

结论

Manifest V3 是一个比 MV2 更受限的平台,其中一些限制要求真正的架构性变更。但这些限制的存在有具体原因:更低的内存消耗、不可审计的远程代码不再存在,以及减少向扩展进程暴露原始网络流量。如果你今天要开发一个新扩展,MV3 是唯一切实受支持的路径。理解 service worker 生命周期和 declarativeNetRequest 模型,正是这项工作的起点。

常见问题

你不应该依赖在内存中保持状态存活。service worker 在空闲时会终止,因此任何内存中的状态都可能丢失。将重要内容持久化到 chrome.storage.local 或 chrome.storage.session,并在 worker 因下一个事件被唤醒时读回来。把每个事件处理器都当作 worker 刚刚启动时一样来对待。

不能。Chrome 团队提供了迁移文档,但架构上的转变 —— service worker 取代 background page、declarativeNetRequest 取代阻塞式 webRequest、不再允许远程代码 —— 通常需要手动重写。只使用简单 API 的扩展可以快速迁移,而依赖持久状态或网络拦截的扩展则需要进行重大重构。

支持。除了在 manifest 中声明的静态规则外,你还可以通过 chrome.declarativeNetRequest.updateDynamicRules 和 updateSessionRules 在运行时添加、删除和更新动态规则及会话级规则。自 MV3 早期版本以来,Chrome 已显著扩展了可用规则配额,使该 API 在许多现代过滤场景中变得切实可用,包括用户可配置的拦截列表。

当你需要与特定网页的 DOM 交互时,使用 content script。当你需要依赖 DOM 的能力 —— 例如解析 HTML、播放音频或使用 Clipboard API —— 但不需要任何关联标签页时,使用 Offscreen API。offscreen 文档运行在扩展自身的上下文中,而不是在某个页面中。

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay