将扩展从 Manifest V2 迁移到 Manifest V3 所需采取的详细步骤

随着 Manifest V3 的引入,我们将禁止远程托管代码。这种机制被不良行为者用作攻击媒介,以规避谷歌的恶意软件检测工具,并对用户隐私和安全构成重大风险。

删除远程托管代码还将使我们能够更彻底、更快速地审查提交给 Chrome 网上应用店的内容。然后,开发人员将能够更快地向他们的用户发布更新。

在扩展团队中,我们认为值得信赖的 Chrome 和值得信赖的扩展体验不仅对用户非常有用,而且对开发人员来说也是必不可少的。从长远来看,Manifest V3 将帮助扩展生态系统继续成为人们可以信任的地方。


随着我们通过继续迭代和改进 Manifest V3 功能来展望未来,我们还希望分享有关逐步淘汰 Manifest V2 扩展计划的详细信息。

淘汰有两个关键日期:

  • 2022 年 1 月 17 日:Chrome 网上应用店将不再接受新的 Manifest V2 扩展。开发者仍可推送现有 Manifest V2 扩展的更新,但不得提交新的 Manifest V2 项目。

  • 2023 年 1 月:Chrome 浏览器将不再运行 Manifest V2 扩展程序。开发人员可能不再向现有 Manifest V2 扩展推送更新。

随着这些日期的临近,我们将分享有关针对更改的 Chrome 版本的更多详细信息,以及有关扩展程序开发人员和用户可能如何受到影响的更多信息。有关更详细的时间线信息,请参阅此页面,随着更准确的日期和里程碑详细信息可用,这些信息将保持更新。

同时,我们将继续根据开发者社区的需求和声音,为 Manifest V3 添加新功能。即使在过去的几个月里,扩展平台也出现了许多令人兴奋的扩展。我们为新的Scripting API引入了额外的机制,并扩展了声明式网络请求 API,支持多个静态规则集、基于选项卡 ID 的过滤和会话范围的规则。

In November 2020, Chrome introduced Manifest V3. For a long time, extensions have been using Manifest V2, so this is a big transition, especially with the new features in V3.2020 年 11 月,Chrome 推出了 Manifest V3。很长一段时间以来,扩展一直在使用 Manifest V2,所以这是一个很大的转变,尤其是在 V3 中的新功能。

In this tutorial, we will see the steps needed to go from Manifest V2 to V3. I will be using the extension from a previous tutorial (在本教程中,我们将看到从 Manifest V2 到 V3 所需的步骤。我将使用上一个教程中的扩展(Chrome Extension Tutorial — Replace Images in Any Website with PikachuChrome 扩展教程——用皮卡丘替换任何网站中的图像) with a  new branch. If you're not familiar with it, we built a chrome extension that replaces all images in a website with random Pikachu images that we retrieved through an API. You can checkout the repository )和一个新的分支。如果您不熟悉它,我们构建了一个 chrome 扩展程序,用我们通过 API 检索到的随机皮卡丘图像替换网站中的所有图像。here您可以在此处.签出存储库


Why Migrate to Manifest V3?为什么要迁移到 Manifest V3?

As Chrome's 正如 Chrome 的Documentation文档 puts it:所说:

Extensions using MV3 will enjoy enhancements in security, privacy, and performance; they can also use more contemporary Open Web technologies adopted in MV3, such as service workers and promises.使用 MV3 的扩展将在安全、隐私和性能方面得到增强;他们还可以使用 MV3 中采用的更现代的开放 Web 技术,例如服务工作者和承诺。

Changes to manifest.jsonmanifest.json 的更改

Changing the Version更改版本

The first obvious step is that you need to change the version of your manifest. In your manifest.json file, change it as follows:第一个明显的步骤是您需要更改清单的版本。在您的 manifest.json 文件中,将其更改如下:

{
	...,
    "manifest_version": 3,
    ...
}

If you try to add your extension to chrome now (or reload it if it's already there), you'll see different errors regarding changes that you still need to make to your manifest.json file.如果您现在尝试将您的扩展添加到 chrome(或者如果它已经存在则重新加载它),您将看到关于您仍需要对 manifest.json 文件进行更改的不同错误。

Host Permissions主机权限

In Manifest V2, there were two ways to get permission for your apis or any host you will need to make requests to from the extension: either in the 在 Manifest V2 中,有两种方法可以为您的 api 或您需要从扩展发出请求的任何主机获取权限:在permissions array or in the 数组中或在optional_permissions array.数组中。

In Manifest V3, all host permissions are now separate in a new array with the key 在 Manifest V3 中,所有主机权限现在都在一个带有 key 的新数组中分开host_permissions. Host permissions should not be added with other permissions anymore.主机权限不应再与其他权限一起添加。

Going back to our example, this was our 回到我们的例子,这是我们的permissions array:数组:

{
	...,
    "permissions": [
    	"https://some-random-api.ml/*"
  	],
    ...
}

Now, it should change to this:现在,它应该变成这样:

{
	...,
    "host_permissions": [
    	"https://some-random-api.ml/*"
  	],
    ...
}

In our case, we just needed to change the key from 在我们的例子中,我们只需要将密钥从 更改permissions to host_permissions. However, if your extension has other values in 但是,如果您的扩展在 中包含其他值permissions, then you should keep them in it and just move your host permissions to ,那么您应该将它们保留在其中并将您的主机权限移动到host_permissions..

Background Scripts背景脚本

Manifest V3 replaces background scripts with service workers. We'll talk about how to make the transition in a bit, but first the transition need to be made in manifest.json.Manifest V3 将后台脚本替换为 Service Worker。我们稍后会讨论如何进行转换,但首先需要在 manifest.json 中进行转换。

The background object currently looks like this in our extension:对象当前在我们的扩展中看起来像这样:

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

What we need to do is change the 我们需要做的是将scripts array key to 数组键更改为service_worker, and now you should have one service worker instead of multiple background pages or scripts. So, it should look like this:,现在您应该拥有一个服务工作者,而不是多个后台页面或脚本。所以,它应该是这样的:

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

Note that we don't need to add 请注意,我们不再需要添加persistent anymore. Also, if you have 此外,如果您有page inside inside background, that should be changed to a service worker as well.,也应该将其更改为 service worker。

Actions行动

Actions used to be Actions 以前是browser_action and and page_action, but now they're unified into ,但现在它们被统一到action in Manifest V3. This is due to the fact that over time they became similar, and separating them became unnecessary. Manifest V3 中。这是因为随着时间的推移它们变得相似,将它们分开变得不必要。

We don't use it in our extension, but this is an example of how it should be like:我们不在我们的扩展中使用它,但这是它应该如何的一个示例:

{
	...,
    "action": {
    	//include everything in browser_action
        //include everything in page_action
    },
    ...
}

There are also changes in the code needed, we will get to that later.所需的代码也有一些变化,我们稍后会谈到。

Content Security Policy内容安全政策

Again, this is not used in our extension, but we still need to go over it. If your extension had a Content Security Policy (CSP), then you need to change it from a string (the way it was in Manifest V2) to an object (the way it is in Manifest v3).同样,这在我们的扩展中没有使用,但我们仍然需要检查它。如果您的扩展程序具有内容安全策略 (CSP),那么您需要将其从字符串(在 Manifest V2 中的方式)更改为对象(在 Manifest v3 中的方式)。

An example of how it should be like in Manifest V3:Manifest V3 中的一个示例:

{
	...,
    "content_security_policy": {
  		"extension_pages": "...",
 	 	"sandbox": "..."
	},
    ...
}

Web-Accessible Resources可访问网络的资源

The last change you need to make in the manifest.json is changing the 您需要在 manifest.json 中进行的最后一项更改是将web_accessible_resources array to an object detailing all the resources. Here's an example of how it should be like in V3:数组更改为详细说明所有资源的对象。这是 V3 中的示例:

{
	...,
    "web_accessible_resources": {
    	"resources": [
        	//the array of resources you had before
        ]
    },
    ...
}

The object also will support in future releases the keys 该对象还将在将来的版本中支持键matches(array of URLs), (URL 数组)、extension_ids(array of keys), and (键数组)和use_dynamic_url(boolean).(布尔值)。

Adding the Extension添加扩展

Now if you go to 现在,如果您在浏览器中转到chrome://extensionschrome://extensions in your browser and add your extension or reload it, it will change to a Manifest V3 extension successfully. However, in our case it will show you an error button in the extension box, and when you click it, it will say "service worker registration failed." That's because there's still more work to do in our code.并添加您的扩展程序或重新加载它,它将成功更改为 Manifest V3 扩展程序。但是,在我们的例子中,它会在扩展框中显示一个错误按钮,当您单击它时,它会显示“服务工作者注册失败”。那是因为在我们的代码中还有更多工作要做。


From Background Scripts to Service Workers从后台脚本到 Service Worker

First, what are service workers and what's the difference between them and background scripts?首先,什么是服务工作者,它们与后台脚本有什么区别?

Background scripts are essential in almost all extensions. They allow you to do some actions or execute code without the need for the user to open a certain page or do something. This can be used to send notifications, manage communication with content scripts, and much more. Background scripts are generally always running in the background.背景脚本在几乎所有扩展中都是必不可少的。它们允许您执行某些操作或执行代码,而无需用户打开某个页面或执行某些操作。这可用于发送通知、管理与内容脚本的通信等等。后台脚本通常总是在后台运行。

Service workers are executed when needed. Unlike background scripts, they are not always running in the background. At the top level, service workers should register listeners to some events that would allow them later on to be executed.服务工作者在需要时执行。与后台脚本不同,它们并不总是在后台运行。在顶层,服务工作者应该注册一些事件的监听器,以便稍后执行它们。

The shift from background scripts to service workers depends on your code in extension. Some extensions might need a lot of reworking, while others not so much.从后台脚本到服务工作者的转变取决于您的扩展代码。一些扩展可能需要大量返工,而另一些则不需要。

The first step you need to do is move your file that was previously a background script or page to the root of the extension. This is actually why in our extension we received the error stating that the registration of the service worker failed. Our background script's path was 您需要做的第一步是将以前是后台脚本或页面的文件移动到扩展的根目录。这实际上就是为什么在我们的扩展中我们收到错误,指出服务工作者的注册失败。我们的后台脚本的路径是js/assets/background.js relative to the root of our extension.相对于我们扩展的根目录的。

If your case is similar, move your background script to the root of your extension, then change the value of 如果您的情况类似,请将后台脚本移动到扩展程序的根目录,然后更改service_worker in your manifest to reflect the change:清单中的值以反映更改:

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

If you reload the extension, the service worker should register successfully.如果您重新加载扩展,服务工作者应该会成功注册。

Now, let's look at the code. In our extension, our background script looked as follows:现在,让我们看一下代码。在我们的扩展中,我们的后台脚本如下所示:

chrome.runtime.onMessage.addListener(function(message, sender, senderResponse){
  if(message.msg === "image"){
    fetch('https://some-random-api.ml/img/pikachu')
          .then(response => response.text())
          .then(data => {
            let dataObj = JSON.parse(data);
            senderResponse({data: dataObj, index: message.index});
          })
          .catch(error => console.log("error", error))
      return true;  // Will respond asynchronously.
  }
});

Basically our background script listened to a message using 基本上,我们的后台脚本使用 监听消息chrome.runtime.onMessage.addListener, and if the message was asking for an image, it would send a request to the API, and then return the data to our content script.,如果消息要求图像,它会向 API 发送请求,然后将数据返回给我们的内容脚本。

Our background script actually does not need any additional change. The reason behind that is that the background script that is now a service worker just registers an event listener and executes code when that event occurs, which is exactly what a service worker should be doing.我们的后台脚本实际上不需要任何额外的更改。其背后的原因是,现在作为 Service Worker 的后台脚本只是注册了一个事件侦听器并在该事件发生时执行代码,这正是 Service Worker 应该做的。

However, not all extensions are like that as there are different use cases. Here's what you need to check for and amend in your background script:但是,并非所有扩展都是这样,因为存在不同的用例。以下是您需要在后台脚本中检查和修改的内容:

Global Variables全局变量

As stated above, background scripts previously were always running in the back. Meaning if I had the following code:如上所述,以前的后台脚本总是在后台运行。意思是如果我有以下代码:

let count = 0;

chrome.runtime.onMessage.addListener( (message) => {
	count++;
    console.log(count);
});

Each time the background script received a message, the count would increment. So, at first it would be 0, then 1, then 2, and so on.每次后台脚本收到一条消息,计数就会增加。所以,一开始它会是 0,然后是 1,然后是 2,以此类推。

In service workers, this will not work anymore. Service workers will run only when they need to, and terminate when they've finished their job. So, the above code would always print in the console "1".在服务人员中,这将不再起作用。Service Worker 只会在需要时运行,并在完成工作后终止。因此,上面的代码将始终在控制台“1”中打印。

Changing this depends on your use case. In the above example, the count could be passed back and forth between your background script and content script to get the result needed. An even better way would be to use Chrome's Storage API. 更改这取决于您的用例。在上面的示例中,可以在后台脚本和内容脚本之间来回传递计数以获得所需的结果。更好的方法是使用 Chrome 的 Storage API。

Using that, the code will look something like this:使用它,代码将如下所示:

chrome.runtime.onMessage.addListener ( (message) => {
	chrome.storage.local.get(["count"], (result) => {
        const count = result.count ? result.count++ : 1;
    	chrome.storage.local.set({count});
        console.log(count);
    });
});

Again, it depends on your code, so make sure to make the changes based on what's best for you.同样,这取决于您的代码,因此请确保根据最适合您的方式进行更改。

Timers and Alarms定时器和警报

Timers were used in background scripts with no problems as they are always running in the background. However, this will not work in service workers. You should replace all timers with the 计时器在后台脚本中使用没有问题,因为它们总是在后台运行。但是,这不适用于服务人员。Alarms API您应该使用Alarms API.替换所有计时器

Accessing the DOM访问 DOM

Service workers do not have access to windows or the DOM. If your extension needs that, you can use libraries like 服务工作者无权访问窗口或 DOM。如果您的扩展需要,您可以使用 jsdom 之类jsdom or use 库或使用chrome.windows.createchrome.windows.create and chrome.tabs.createchrome.tabs.create. It depends on your usage and what fits your needs.这取决于您的使用情况以及适合您的需求。

This is also needed if your background scripts record audio or video, as that is not possible in service workers.如果您的后台脚本录制音频或视频,这也是必需的,因为这在服务人员中是不可能的。

Creating Canvas创建画布

If your background script previously created canvas, you can still do that with the 如果您的后台脚本之前创建了画布,您仍然可以使用OffscreenCanvasOffscreenCanvas API. All you have to do is replace API 来执行此操作。您所要做的就是替换document with OffscreenCanvas..

For example, if this was your code:例如,如果这是您的代码:

let canvas = document.createElement('canvas');

Then you should change it to:然后你应该把它改成:

let canvas = new OffscreenCanvas(width, height);

Checking Your Extension检查你的扩展

After you are done with making the changes need to change your background script to a service worker, reload your extension in the browser to see if it is working properly.完成更改后,需要将后台脚本更改为服务工作者,在浏览器中重新加载扩展程序以查看它是否正常工作。

In our case, there was no change needed in background.js other than moving it to the root. So, if you reload the extension and go to a page, you will find that images have been replaced with Pikachu images successfully.在我们的案例中,除了将其移至根目录外,无需进行任何更改。因此,如果您重新加载扩展程序并转到某个页面,您会发现图像已成功替换为皮卡丘图像。


Actions API操作 API

As mentioned before, 如前所述,browser_action and 现在page_action are now merged into 合并到action. The same should be applied in your code. If you are using 在您的代码中也应该应用同样的方法。如果您正在使用browserAction or pageAction like below:如下所示:

chrome.browserAction.onClicked.addListener(tab => {});
chrome.pageAction.onClicked.addListener(tab => {});

It should be changed to use the new Actions API as follows:应将其更改为使用新的 Actions API,如下所示:

chrome.action.onClicked.addListener(tab => {});

So, make sure to replace all 因此,请确保将所有browserAction and pageAction usages with 用法替换为action..


executeScript执行脚本

If your code executed arbitrary strings using executeScript's 如果您的代码使用 executeScript 的code property, you have two ways to change it. Also, instead of using 属性执行任意字符串,您有两种方法可以更改它。此外,chrome.tabs.executeScript, you need to replace 您需要替换tabs with 为,而不是使用 ,scripting so that it will be 以便将其替换为chrome.scripting.executeScript.

Moving the Code To a New File将代码移动到新文件

You need to move the value of 您需要将 的值移动code to a new file and use executeScript's 到新文件并使用 executeScript 的file property.属性。

For example, if your code had something like this:例如,如果您的代码有这样的内容:

chrome.tabs.executeScript({
    code: alert("Hello, World!")
});

You should move the value of 您应该将 的值移动code, which here is alert("Hello, World!") to a new file (let's call it 一个新文件中(我们称之为hello-world.js):):

alert("Hello, World!");

Then change your previous code to the following:然后将您之前的代码更改为以下内容:

chrome.scripting.executeScript({
    file: 'hello-world.js'
});

Put the Code in a Function将代码放入函数中

If your code can be put in a function instead, like the example code, then just move it to a function in the same file, then assign the 如果您的代码可以放入函数中,例如示例代码,那么只需将其移动到同一文件中的函数中,然后将function property of 属性分配给executeScripts to the function you created:您创建的函数:

function greeting() {
    alert("Hello, World!");
}

chrome.scripting.executeScript({
    function: greeting
});

Additional Work额外工作

There is a list of other changes and things you need to look for in your code:您需要在代码中查找其他更改和内容的列表:

  1. If your extension uses the webRequest API, which is typically used in an enterprise setting where the extension is forced-installed, you need to replace it with the 如果您的扩展程序使用 webRequest API(通常在强制安装扩展程序的企业环境中使用),您需要将其替换为declarativeNetRequestdeclarativeNetRequest API. API。
  2. If you are making any CORS requests in your content scripts, make sure to move them to your service worker.如果您在内容脚本中发出任何 CORS 请求,请确保将它们移至您的服务工作者。
  3. Remotely-hosted code is not allowed anymore. You need to find another way to execute your remotely hosted code. Chrome's documentation suggests using either 不再允许远程托管代码。您需要找到另一种方法来执行您的远程托管代码。Chrome 的文档建议使用Configuration-driven features and logic 配置驱动的功能和逻辑which means you retrieve a JSON file with the configuration needed and you cache it locally for later use, or ,这意味着您可以检索具有所需配置的 JSON 文件并将其缓存在本地以供以后使用,或者使用Externalize logic with a remote service 远程服务将逻辑外部which means you have to move your application logic from your extension to a remote web service.化,这意味着您必须从扩展程序中移动应用程序逻辑到远程 Web 服务。
  4. Check the 检查API ReferenceAPI 参考 for any deprecated APIs or methods you might be using.以了解您可能正在使用的任何已弃用的 API 或方法。

在接下来的几个月中,我们还将推出对动态可配置内容脚本和内存存储选项的支持,以及其他新功能。这些更改是在考虑社区反馈的情况下制定的,随着开发人员分享有关其迁移挑战和业务需求的更多信息,我们将继续构建更强大的扩展 API 功能。最后,我们将继续与 Web Extensions Community Group 中的其他浏览器供应商合作,在平台上进行迭代并追求通用的跨浏览器扩展模型。

如果您对 Manifest V3 有反馈或在迁移过程中遇到独特的挑战,请发布到chromium-extensions Google Group。越早提出问题并提供越早的反馈,团队在 Manifest V2 淘汰之前解决这些问题的选项就越多。

没有评论:

发表评论

Follow Us

FOLLOW US

Blog Archive

Comments

Blogger 提供支持.

Search This Blog

Tags

header ads