Manifest V3

extension
Created 9/17/2022
Updated 4/17/2023

Manifest V3

每一个扩展程序都需要有一个配置清单 manifest.json 文档,它提供了关于扩展程序的基本信息,例如所需的权限、名称、版本等。

当前配置清单类型最新的版本是 Manifest V3,简称 MV3,遵循该配置清单版本的扩展程序,会更注重安全和用户的隐私保护,在性能方面也会得到提升,同时开发简易性和功能实现也会更佳。

注意

Chrome 88 版本开始支援配置清单为 Manifest V3 版本的扩展程序,Chrome 网上应用店从 2021 年 1 月开始支持分发配置清单为 Manifest V3 版本的扩展程序。

提示

谷歌在 2019 年的 Chrome Dev Summit 中介绍了 Manifest V3,可以查看这个 🎬 视频

特点概述

MV3 有多个新增特性,常用功能的变动如下:

  • 使用 Service workers 替代了后台页面 background pages
    后台脚本运行在 Service workers 环境中,其工作方式是基于监听-响应的模式的,它不会常驻后台可以提升性能;但由于运行环境没有后台页面,因此无法使用与 DOM 相关的 API
  • 再支持从外部服务器(一般是 CDN)获取代码,如 JavaScript 脚本或 Wasm 文件
    扩展程序只能执行在应用内部的脚本,以提高安全性。如果扩展程序需要依赖外部数据,推荐以配置参数文件的形式进行传递
  • 很多 API 都支持 Promise
    对于异步方法现在可以使用 promise 链或 async/await 进行操作。传统以回调函数的方式处理异步方法,也依然支持(为了兼容性,但是旧方法就不会返回 promise),对于一些场景,例如事件监听,还需要设置回调函数(作为事件处理函数)
  • 统一的 Action API
    全局的图标交互控件 Browser Action 和特定页面的图标交互控件 Page Action 合并为 Action API
  • 内容脚本 content scripts 支持在运行时才动态注册并植入
  • 提供一个新的 API 获取网页的图标 favicons,以替代 chrome://favicons
  • Storage API 提供一个新的 StorageArea 类型,以允许将数据存储在内存中,便于 service worker 重启时快速读取
Tip

未来 Chrome 还会支持更多关于扩展程序的新特性,可以随时关注查看这个页面 What's new in Chrome extensions

常见配置项

每一个扩展程序都需要有一个配置清单 manifest.json 文档,它提供了关于扩展程序的基本信息,例如所需的权限、名称、版本等。

以下列出了 MV3 版本中常见的配置项,对于每一项的具体作用可以参考官方文档的相应页面

manifest.json
json
{
  // 必须
  "manifest_version": 3, // 目前配置清单的最新版本是 3
  "name": "My Extension", // 扩展程序名称
  "version": "versionString", // 扩展程序的版本

  // 推荐
  "action": {...}, // 与 Action 交互控件相关的设置,它是浏览器工具栏上的扩展程序图标相关的一系列配置
  "default_locale": "en", // 默认语言
  "description": "A plain text description", // 扩展程序的描述
  "icons": {...}, // 扩展程序的图标

  // 可选
  "author": ...,
  "automation": ...,
  "background": {
    // Required
    "service_worker": "service-worker.js",
    // Optional
    "module"
  },
  "chrome_settings_overrides": {...},
  "chrome_url_overrides": {...},
  "commands": {...},
  "content_scripts": [{...}],
  "content_security_policy": {...},
  "cross_origin_embedder_policy": {...},
  "cross_origin_opener_policy": {...},
  "declarative_net_request": ...,
  "devtools_page": "devtools.html",
  "event_rules": [{...}],
  "export": {...},
  "externally_connectable": {
    "matches": ["*://*.example.com/*"]
  },
  "file_browser_handlers": [...],
  "file_system_provider_capabilities": {
    "configurable": true,
    "multiple_mounts": true,
    "source": "network"
  },
  "homepage_url": "https://path/to/homepage",
  "host_permissions": [...],
  "import": [{"id": "abc"}],
  "incognito": "spanning, split, or not_allowed",
  "input_components": [{...}],
  "key": "publicKey",
  "minimum_chrome_version": "107", // 该扩展程序所兼容的 Chrome 的最低版本
  "oauth2": ...,
  "offline_enabled": true,
  "omnibox": {
    "keyword": "aString"
  },
  "optional_host_permissions": ["..."],
  "optional_permissions": ["tabs"],
  "options_page": "options.html",
  "options_ui": {
    "chrome_style": true,
    "page": "options.html"
  },
  "permissions": ["tabs"],
  "requirements": {...},
  "sandbox": [...],
  "short_name": "Short Name",
  "storage": {
    "managed_schema": "schema.json"
  },
  "system_indicator": ...,
  "tts_engine": {...},
  "update_url": "https://path/to/updateInfo.xml",
  "version_name": "1.0 beta",
  "web_accessible_resources": [...]
}
说明

在扩展程序的配置清单 manifest.json 中必须的字段只有 3 个

  • manifest.json
  • name
  • version

而且在开发模式下该文件中可以带有注释内容,但是提交到 Chrome Web Store 时需要将其中的注释移除

迁移指南

参考

以下介绍从 MV2 迁移到 MV3 需要注意的一些常见要点:

升级配置清单 manifest 文档

  • 更改版本配置选项 manifest_version: 3
  • 在 MV3 中新增了配置选项 host_permissions 以声明允许扩展程序访问哪些安全的域名
    提示

    You do not have to declare content script match patterns in host_permissions in order to inject content scripts. However, they are treated as host permissions requests by the Chrome Web Store review process.

    官方文档是这一段说明,指配置选项 host_permissions 是可选的,在其中可以声明网页的匹配规则/模式,以表示 content script 内容脚本支持植入哪些类型的网页。如果声明了该配置选项,就会在 Web Store 审核时将它们看作是该插件会作出的主机请求。

  • 将选项 page_actionbroser_action 进行必要的删减,合并为统一的 action 选项

脚本执行

  • MV3 不允许执行从外部服务器(一般是 CDN)获取的脚本文件,需要更新这部分的代码逻辑,要将依赖的模块脚本预先整合到扩展程序内,如果你需要依赖外部服务器,可以有两个解决方案:
    • 将代码逻辑进行拆分,从原来的加载整包代码变成配置驱动,即将核心代码保留在扩展程序内,将配置文件外置在服务器中,在运行扩展程序时只需要从远端服务器获取相应的配置参数即可
    • Externalize logic with a remote service
  • 植入内容脚本的方法更改为 chrome.scripting.executeScript()。类似地,植入 CSS 相关方法 insertCSS()removeCSS() 也从 chrome.tabs API 更改为 chrome.scripting API
  • 在 MV3 中执行的内容脚本代码,只能是以脚本文件(数组)files: ['content-script.js'] 或是函数 func: functionName(执行环境上下文并不同步传递植入,需要以参数 args 的形式传递)的形式呈现,而不能是任意的字符串形式
    background.js
    js
    // Manifest V3
    async function getCurrentTab() {/* ... */}
    let tab = await getCurrentTab();
    
    // file format
    chrome.scripting.executeScript({
      target: {tabId: tab.id},
      files: ['content-script.js']
    });
    
    // function format
    function showAlert(givenName) {
      alert(`Hello, ${givenName}`);
    }
    
    let name = 'World';
    chrome.scripting.executeScript({
      target: {tabId: tab.id},
      func: showAlert,
      args: [name],
    });
    

后台脚本

后台脚本在 service workers 环境中执行

这是 MV3 一个很明显的非兼容式改变,会影响大部分 MV2 版本的扩展程序的升级,需要对原来后台页面 background page 的代码逻辑进行重构。

在迁移时,需要记住以下两点:

  • Service workers 是基于事件-响应模式实现功能的(就像之前 MV2 的 event pages),它并不会常驻在后台,只有在相应的事件触发时才重新运行
  • Service workers 环境中无法访问 DOM,因此无法使用相关的 API

如果要使用后台脚本,需要先在配置清单 manifest.json 的选项 background.service_work 中声明/注册需要运行的(单个)后台脚本

json
{
  // ...
  "background": {
    "service_worker": "background.js"
  },
}

在后台脚本的逻辑代码中,需要在事件循环的第一轮中完成事件监听的注册,即将事件监听程序写在后台脚本最顶层的作用域中,而不应该内嵌在其他的逻辑代码中(因为 Service Workers 执行完代码会终止而不会长期驻留,当有事件需要分派时它才再次运行,如果未能在第一次事件轮询中注册监听器,这就无法响应事件)

background.js
js
chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
  chrome.action.setBadgeText({ text: badgeText });
});

// Listener is registered ⚠️ on startup
chrome.action.onClicked.addListener(handleActionClick);

由于 Service workers 无法常驻后台,因此对于需要持久化的数据,可以使用 Storage API 将其保存,待 Service workers 重启时再从数据库读取。

js
// background.js
chrome.runtime.onMessage.addListener(({ type, name }) => {
  if (type === "set-name") {
    chrome.storage.local.set({ name });
  }
});

chrome.action.onClicked.addListener((tab) => {
  chrome.storage.local.get(["name"], ({ name }) => {
    chrome.tabs.sendMessage(tab.id, { name });
  });
});

由于 Service workers 无法访问 DOM 和相关的 API,所以无法使用方法 window.setTimeout()window.setInterval(),因为在 Service workers 环境中没有 window 这个变量对象。如果后台脚本需要使用调度实现功能,可以使用 Alarms API 代替

background.js
js
chrome.alarms.create({ delayInMinutes: 3 });

chrome.alarms.onAlarm.addListener(() => {
  chrome.action.setIcon({
    path: getRandomIconPath(),
  });
});

失效的 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

还有一些未在文档中明确声明的已失效的 API

  • chrome.extension.sendMessage()
  • chrome.extension.connect()
  • chrome.extension.onConnect
  • chrome.extension.onMessage

检查清单

在实际操作时可以使用迁移清单进行对照检查:

  • API 检查
    • 在原来的项目中是否设置了域名访问的权限,在 MV3 的配置清单 manifest.json 中有一个新增的选项 host_permissions 专门设置域名许可
    • 在原来的项目中是否使用了后台页面 background page,在 MV3 需要将后台脚本迁移到 Service workers 中。
      • 需要先在配置清单 manifest.json 的选项 background.service_work 中声明注册需要运行的(单个)后台脚本
      • 移除原有的 background.persistent 选项
      • 需要重构后台脚本代码以适用 Service workers 基于事件-响应的模式
      • 无法使用相关的 API 实现后台页面与内容脚本之间的通讯,如 chrome.runtime.getBackgroundPage(), chrome.extension.getBackgroundPage(), chrome.extension.getExtensionTabs()chrome.extension.getViews(),需要使用信息传递 message passing 相关 API
    • 在原来的项目的配置清单中是否声明了 browser_actionpage_action 交互控件,在 MV3 中它们被统一到 action。相应地,在后台脚本 background script 中 chrome.browserAction API 和 chrome.pageAction API 需要被替换为 chrome.action API
    • 在原来的项目中是否使用了 chrome.webRequest 进行监听或拦截网络请求,在 MV3 中替换为 declarativeNetRequest API
    • 在原来的项目中是否使用 chrome.tabs API 植入脚本和样式文件,在 MV3 中需要使用 chrome.scripting API,
      Manifest V2Manifest V3
      chrome.tabs.executeScript()chrome.scripting.executeScript()
      chrome.tabs.insertCSS()chrome.scripting.insertCSS()
      chrome.tabs.removeCSS()chrome.scripting.removeCSS()
    • 在原来的项目中是否需要运行从外部服务器获取的脚本,在 MV3 中不允许执行从外部获取的代码,需要将这些脚本预先整合到扩展程序中。
  • 安全性检查
    • 在原来的项目中是否通过内容脚本 content script 进行跨域请求,由于 MV3 的内容脚本 content script 符合同源政策的限制,需要将网络请求迁移到 Service workers 后台脚本中
    • 在原来的项目中是否在配置清单中定制了 content_security_policy,在 MV3 中使用 content_security_policy.extension_pagescontent_security_policy.sandbox 进行替代,移除与外部域相关的设置,如 script-srcworker-srcobject-srcstyle-src

Copyright © 2024 Ben

Theme BlogiNote

Icons from Icônes