Manifest V3 从 Chrome 88 版本开始可用。
V3 新特性
- Service workers 替换 background pages
- 网络请求的修改现在使用新的API
declarativeNetRequest
处理 - 不再支持加载远程托管的代码(Javascript or Wasm)。扩展程序现在只能执行包内部的 Javascript。
- 许多 API 方法现在原生支持 Promise,可选的 callback 回调方式依然支持
主要特性
Service workers
从 background pages 到 Service workders 是一种底层机制的改变。
同web service worker 一样,它监听并响应事件,也负责管理缓存、预加载资源和启用离线网页这些事情。但 extension service workders 更专注于对扩展程序 API 暴露的浏览器事件做出相应的响应。也就是说,现在对于浏览器事件响应更快更高效,用户体验更好。主要是在于性能上的提升。
网络请求修改
V3 提供了一个新的 API declarativeNetRequest 来用于修改和阻塞网络请求。这种方式隐私保护更好,性能更加。该 API 的本质特征是:
- 相比于之前拦截一个请求和程序式地修改它,新 API 委托 Chrome 浏览器自身来计算和修改请求
- 你需要声明一系列的规则: 匹配的请求模式和匹配时要执行的操作。然后,浏览器按照这些定义的规则修改网络请求
在V3 中 webRequest
API的阻塞方式被限制为强制安装的扩展使用。
网络请求的修改我们这里不详细展开讨论,如果开发中有需要可以查看相应的 API 文档。
远程托管代码
不再支持加载远程托管的代码主要出于两个原因:
- 安全因素,远程代码总是有不安全因素存在
- Chrome 在审核提交的插件时更可靠,更高效,不需要再去关注远程代码,只需要审核包内的代码即可。
Promises
V3 现在原生支持 Promise。许多常用 API 现在都支出,最终所有合适的 API 都会支持 Promise。
如果使用 callback,就不会返回 Promise,优先执行 callback。
不管我们在开发中是否使用了
webextension-polyfill
库,callback 的方式仍然支持,但现在推荐使用 Promise 或 async/await 的方式。
其他特性
- Action API 整合:Browser Action 和 page Action 被统一整合到一个单独的 Action API
- web可访问资源:现在必须指定站点和插件
- 内容安全策略(CSP)
- executeScript() 变化:不再执行任意的字符串,仅支持脚本文件和函数
还有一些马上即将加入的新特性:
- 动态 content Scripts
- 新的 favicon API
- 内存存储(in-memory storage)
迁移到 V3
更新 manifest.json 文件
首先就是更改 manifest_version 的值为 "3"
manifest 版本
// Manifest V2
"manifest_version": 2
// Manifest V3
"manifest_version": 3
更改 manifest_version 后,只要不符合 V3 要求的都会报错提示,注意查看。只要不报错,就符合 V3 规范。
Host 权限
V3 将 permissions
拆分开来,host 相关的权限添加到 host_permissions
下:
// Manifest V2
"permissions": [
"tabs",
"bookmarks",
"http://www.blogger.com/",
],
"optional_permissions": [
"*://*/*",
"unlimitedStorage"
]
// Manifest V3
"permissions": [
"tabs",
"bookmarks"
],
"optional_permissions": [
"unlimitedStorage"
],
"host_permissions": [
"http://www.blogger.com/",
"*://*/*"
],
内容安全策略
V2 需要指定一个字符串,V3 是一个对象:
// Manifest V2
"content_security_policy": "..."
// Manifest V3
"content_security_policy": {
"extension_pages": "...",
"sandbox": "..."
}
Action API 统一
browser_action
和 page_action
统一到一个单独的 action
API:
// Manifest V2
// manifest.json
{
"browser_action": { … },
"page_action": { … }
}
// background.js
chrome.browserAction.onClicked.addListener(tab => { … });
chrome.pageAction.onClicked.addListener(tab => { … });
// Manifest V3
// manifest.json
{
"action": { … }
}
// background.js
chrome.action.onClicked.addListener(tab => { … });
web可访问资源
此更改将扩展资源的访问限制在特定的站点/扩展。 现在提供的不再是文件列表,而是对象列表,每个对象都可以映射到一组资源到一组url或扩展id:
// Manifest V2
"web_accessible_resources": [RESOURCE_PATHS]
// Manifest V3
"web_accessible_resources": [{
"resources": [RESOURCE_PATHS],
"matches": [MATCH_PATTERNS],
"extension_ids": [EXTENSION_IDS],
optional "use_dynamic_url": boolean
}]
matches
字段提供的模式字符串,后面必须包含*
号,不指定星号会报错,无法加载 manifest。更详细讲解请参考:Manifest - Web Accessible Resources - Chrome Developers
执行代码
如果在 V2 中执行了远程托管代码,注入代码字符串到页面或者在运行时阶段 eval() 代码字符串。你需要在V3中做相应更新。
// Manifest V2:
chrome.tabs.executeScript()
chrome.tabs.insertCSS()
chrome.tabs.removeCSS()
// Manifest V3:
chrome.scripting.executeScript()
chrome.scripting.insertCSS()
chrome.scripting.removeCSS()
远程托管代码
下面两种都被认为是远程托管代码:
- 从服务器获取的 javaScript 文件
- 在运行时阶段传入
eval()
的代码字符串
如果真的有需要,我们仍然有其他可选方案可用:
- 配置驱动的功能和逻辑—在运行时加载远程配置(例如 JSON 文件),并在本地缓存。扩展然后使用这个缓存的配置来决定开启哪些功能和逻辑。
- 使用远程服务器,逻辑外部化—将某些程序逻辑迁移到远程web服务器。
执行任意字符串
V2 允许执行任意的代码字符串在 tabs.executeScript()
选项对象的 code
属性上。V3 不再允许。
注入静态文件用法的更改:
// Manifest V2
// background.js
chrome.tabs.executeScript({
file: 'content-script.js'
});
// content-script.js
alert('File test alert');
// Manifest V3
// background.js
async function getCurrentTab() {/* ... */}
let tab = await getCurrentTab();
chrome.scripting.executeScript({
target: {tabId: tab.id},
files: ['content-script.js']
});
// content-script.js
alert('File test alert');
func
属性和 args
属性用于注入一个函数。这个函数并不是在content script中运行的,它被发送到目标 tab 并在那里运行。
// Manifest V2
// background.js
let name = 'World!';
chrome.tabs.executeScript({
code: `alert('Hello, ${name}!')`
});
// Manifest V3
// background.js
async function getCurrentTab() {/* ... */}
let tab = await getCurrentTab();
function showAlert(givenName) {
alert(`Hello, ${givenName}`);
}
let name = 'World';
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: showAlert,
args: [name],
});
这里是其用法的一个官方例子:chrome-extensions-samples/popup.js at main · GoogleChrome/chrome-extensions-samples · GitHub
Background service workers
什么是 Service Worker?
一句话解释就是:service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don't need a web page or user interaction.
Service Worker 延展介绍: Service Worker
// MV2
"background": {
"scripts": ["background.js"],
"persistent": false
}
// MV3
"background": {
"service_worker": "background.js"
}
迁移到新的 background 环境,有两个主要点需要记住:
- service worker在不使用时被终止,在需要时重新启动(类似于event page,即
"persistent": false
)。 - service worker没有访问DOM的权限。
Service worker也带来了 background 使用上的一些变化,这里不详细展开,请查看官网文档:Migrating from background pages to service workers - Chrome Developers
修改网络请求
这里不展开介绍,有需要大家查阅官方文档:Migrating to Manifest V3 - Chrome Developers
弃用的 API
V3 将会移除这些弃用的 API,如果在 V2 项目中有使用这些 API,你需要做合适的更改。这些 API 包括:
chrome.extension.sendRequest()
chrome.extension.onRequest
chrome.extension.onRequestExternal
chrome.extension.lastError
chrome.extension.getURL()
chrome.extension.getExtensionTabs()
chrome.tabs.Tab.selected
chrome.tabs.sendRequest()
chrome.tabs.getSelected()
chrome.tabs.getAllInWindow()
chrome.tabs.onSelectionChanged
chrome.tabs.onActiveChanged
chrome.tabs.onHighlightChanged
As well as the undocumented:
chrome.extension.sendMessage()
chrome.extension.connect()
chrome.extension.onConnect
chrome.extension.onMessage
如何迁移V3时,替换这些废弃API?官网在 API 文档中会明确提示的。以 chrome.tabs.sendRequest()
为例:
可以看到已经提示你去使用 runtime.sendMessage()
。
查阅官方文档时,那些标签也能帮助到我们。
Promise
标签:支持 Promise
<=MV2
标签:该API仅在V2前支持
>=MV3
标签:该API在V3后支持
Deprecated
标签:已废弃的 API