chrome 插件开发指南(Manifest V3) - 掘金

标签: | 发表时间:2023-03-30 20:33 | 作者:
出处:https://juejin.cn

一、什么是 Chrome插件

1.1 概述

严格来讲,我们正在说的东西应该叫 Chrome 扩展(Chrome Extension),真正意义上的 Chrome 插件是更底层的浏览器功能扩展,需要对浏览器源码有一定掌握才有能力去开发。鉴于 Chrome 插件的叫法已经习惯,本文中也全部采用这种叫法。在百度指数里也没有收录“chrome 扩展”这个词,只有“chrome 插件”。

Chrome 插件是一个用 Web 技术开发、用来增强浏览器功能的软件,它其实就是一个由HTML、CSS、JS、图片等资源组成的一个.crx后缀的压缩包。

另外,其实不只是前端技术,Chrome 还可以配合 C++ 编写的 dll 动态链接库实现一些更底层的功能(NPAPI),比如全屏幕截图等。

由于安全原因,Chrome 浏览器42以上版本已经陆续不在支持 NPAPI 插件,取而代之的是更安全的 PPAPI。

1.2 Chrome 插件是如何工作的

扩展是基于诸如 HTML、 JavaScript 和 CSS 之类的 Web 技术构建的。它们运行在一个独立的沙箱执行环境中,并与 Chrome 浏览器进行交互。

image.png
从图中可以看出,存在三个进程: 扩展进程(Extension Process)、 页面渲染进程(Render Process)、 浏览器进程(Browser Process)。
1)扩展进程中运行Extension Page,Extension Page主要包括backgrount.html和popup.html:

  • backgrount.html中没有任何内容,是通过background.js创建生成,当浏览器打开时,会自动加载插件的background.js文件,它独立于网页并且一直运行在后台,它主要通过调用浏览器提供的API和浏览器进行交互;
  • popup.html则不同,它有内容,是一个实实在在的页面,和我们普通的web页面一样,由html、css、Javascript组成,它是按需加载的,需要用户去点击地址栏的按钮去触发,才能弹出页面。

2)渲染进程主要运行Web Page,当打开页面时,会将content_script.js加载并注入到该网页的环境中,它和网页中引入的Javascript一样,可以操作该网页的DOM Tree,改变页面的展示效果;
3)浏览器进程在这里更多起到桥梁作用,作为中转可以实现Extension Page和content_script.js之间的消息通信。

1.3 延伸阅读:插件和扩展的区别

扩展(Extension)指的是通过调用 Chrome 提供的 Chrome API 来扩展浏览器功能的一种组件,工作在浏览器层面,使用 HTML + Javascript 语言开发。比如著名的 AdBlock plus。

插件(Plug-in)指的是通过调用 Webkit 内核 NPAPI 来扩展内核功能的一种组件,工作在内核层面,理论上可以用任何一种生成本地二进制程序的语言开发,比如C/C++、Delphi等。比如Flash player插件,就属于这种类型。一般在网页中 object 或者 embed 标签声明的部分,就要靠插件来渲染。

从安全性上来看,由于插件一般实现的都是比较底层的功能,所以一旦出现问题,往往就会牵涉到整个操作系统,像 Flash 就属于经常被扒出高危漏洞的那一类。相比较之下,扩展出现问题,其危害性往往类似于浏览器漏洞。不过 Chrome Extension 在为用户带来便利的同时,也的确带来了不少安全问题,即便是在 Chrome 应用商店中的应用也不能保证绝对安全,Google 自己也下线过一些有安全隐患的扩展。

二、Chrome 插件能做什么

image.png
扩展允许你通过使用 API 修改浏览器行为和访问网页内容来“扩展”浏览器。
扩展 API 允许扩展的代码访问浏览器本身的特性: 激活选项卡、修改网络请求等等。

插件能力概述:

API 备注
自定义扩展用户界面 控制一个扩展的显示的图标 Action
添加触发操作的键盘快捷键 Commands
添加页面右键菜单 Context Menus
向地址栏添加关键字功能 Omnibox
创建新标签卡、书签页或历史记录页 Override Pages
在工具栏中动态显示图标。 Page Actions
构建扩展工具 无障碍扩展服务 Accessibility (a11y)
有趣的事情发生时,做出检测和反应 Service Workers
使用语言和语言环境 Internationalization
获得OAuth2访问令牌 Identity
管理已安装和正在运行的扩展插件 Management
通过 Content Script 与其父扩展进行通信 Message Passing
让用户自定义扩展 Options Pages
修改一个扩展的权限 Permissions
存储和检索数据 Storage
修改和监听 Chrome 浏览器 创建、组织和操作书签行为 Bookmarks
从用户的本地配置文件中删除浏览数据 Browsing Data
以编程方式启动、监视、操作和搜索下载 Downloads
管理 Chrome 的字体设置 Font Settings
与浏览器访问页面的记录交互 History
控制 Chrome 的隐私特性 Privacy
管理 Chrome 的代理设置 Proxy
从浏览会话查询和还原选项卡和窗口 Sessions
在浏览器中创建、修改和重新排列选项卡 Tabs
访问用户访问次数最多的 URL Top Sites
更改浏览器的整体外观 Themes
在浏览器中创建、修改和重新排列窗口 Windows
修改和监听网页 扩展临时访问当前活动选项卡的权限 Active Tab
自定义网站特性,如 cookies、 JavaScript 和插件 Content Settings
在网页上下文中运行 JavaScript 代码 Content Scripts
浏览和修改浏览器的 Cookie 系统 Cookies
使用 XMLHttpRequest 从远程服务器发送和接收数据 Cross-Origin XHR
在不需要许可的情况下对页面内容执行操作 Declarative Content
捕获屏幕、单个窗口或选项卡的内容 Desktop Capture
将选项卡的源信息保存为 MHTML Page Capture
与标签页互动媒体流交互 Tab Capture
接收 in-flight 导航请求状态的通知 Web Navigation
提供规则告诉 Chrome 如何拦截、阻止或修改 in-flight 的请求。 Declarative Net Request
打包、部署和更新 使用 Chrome Web Store 托管和更新扩展 Chrome Web Store
在指定的网络或其他软件上分发扩展 Other Deployment Options
扩展 Chrome DevTools 测试网络交互,调试 JavaScript,修改 DOM 和 CSS Debugger
为 Chrome 开发工具添加功能 Devtools

几个插件例子:

image.png image.png image.png image.png
Google 翻译 Adblock Plus Artemis and Britomartis Octotree - GitHub code tree)

一句话总结: Chrome扩展插件是用前端的技术栈,来定制浏览器的功能,改善用户体验

三、主要构成

image.png一个chrome插件通常由3类文件组成:

  1. 配置文件 manifest.json
  2. 图片、css等资源文件
  3. js脚本文件,包括popup.js、background.js、content_script.js等

3.1 Manifest.json

每一个扩展都有一个json格式的清单文件,用于配置扩展的名称、版本号、图标、权限、脚本路径等信息;
文件内容如下所示:

      {"manifest_version":3,"name":"MStars","description":"A chrome extension for sgfe","options_page":"options.html","background":{"service_worker":"background.bundle.js"},"action":{"default_popup":"popup.html","default_icon":"master-34.png"},"chrome_url_overrides":{"newtab":"newtab.html"},"icons":{"128":"master.png"},"content_scripts":[{"matches":["http://*/*","https://*/*","<all_urls>"],"js":["contentScript.bundle.js"],"css":["content.styles.css"]}],"web_accessible_resources":[{"resources":["injectScript.bundle.js","content.styles.css","master.png","master-34.png","vs/*"],"matches":["http://*/*","https://*/*","<all_urls>"]}],"permissions":["webRequest","storage","contextMenus","bookmarks"],"host_permissions":["<all_urls>"],"content_security_policy":{"extension_pages":"script-src 'self';object-src 'none'"}}复制代码

3.1.1 Manifest V2

自2022年1月17日起,Chrome 应用商店已经停止接受新的 Manifest V2扩展。
2023年6月 Chrome 115开始,关闭对 Manifest V2扩展的支持。
2024年1月,Chrome 应用商店将删除所有的 Manifest V2扩展。
image.png
(Manifest V2 support timeline)

3.1.2 Manifest V3

2020年年底推出V3版本,在安全性、隐私性和性能方面得到了增强;还可以使用更现代的开放 Web 技术,比如 service workspromises

Manifest V3 is available beginning with Chrome 88, and the Chrome Web Store begins accepting Manifest V3 extensions in January 2021.

详细文档: developer.chrome.com/docs/extens…

3.2 popup

3.2.1 概述

popup 是点击插件图标时打开的一个页面,点击 popup 之外的区域会收起,一般用来做一些临时性的交互。
image.png
(Web Vitals)

3.2.2 简单例子

1、 创建 manifest.json 文件:

      {"manifest_version":3,"name":"Hello Extensions","description":"Base Level Extension","version":"1.0","action":{"default_popup":"hello.html","default_icon":"hello_extensions.png"}}复制代码

2、创建 html 文件:

      <html><body><h1>Hello Extensions</h1></body></html>复制代码
  1. 点击 action 后,就会看到:
    image.png

3.3 content-scripts

3.3.1 概述

content-scripts 是在网页上下文中运行的文件。通过使用标准的文档对象模型(Document Object Model,DOM) ,它们能够读取浏览器访问的网页的详细信息,对它们进行更改。

如主题、样式、布局定制、广告拦截等等。

大部分浏览器插件都在围绕 content-scripts 做一些事情,background、popup、options等都为之服务。
配置示例:

      "content_scripts":[{"matches":["http://*/*","https://*/*","<all_urls>"],"js":["contentScript.bundle.js"],"css":["content.styles.css"]}],复制代码

3.3.2 特性

1)和原始页面共享 DOM,但是不能共享 JS,不能访问页面中的 JS(比如变量)。
2)网络请求受到同源策略限制。
3)只能访问以下 Chrome API:

其他 API 都不能直接访问,但是可以通过通信让 background 来进行调用。

3.3.3 简单例子

在页面中增加一个按钮。

      functioninJectBtn() {if(document.querySelector('#openInIDE'))return;document.querySelector('.repo-detail-base-info .btn-box')
    .insertAdjacentHTML('beforeend','<button id="openInIDE" type="button" class="mtd-btn mtd-btn-warning"><span><div class="mtd-button-content"><span class="mtdicon mtdicon-link-o"></span><span>Open In WebIDE</span></div></span></button>');document.querySelector('#openInIDE').addEventListener('click',() =>{window.open('https://xxx.com/');
  });
}functioninit() {varheartBeat =setInterval(() =>{varwantedEl =document.querySelector('.repo-detail-base-info .btn-box');if(wantedEl) {clearInterval(heartBeat);inJectBtn();
    }
  },1000);
}init();复制代码

3.3.4 延伸阅读:如何访问页面中的 JS

content-scripts 不能访问页面中的 js,它可以操作 DOM,但是 DOM 却不能调用它,所以就有了通过 DOM 操作的方式向页面动态注入 JS 的操作。

      functioninjectJs(jsPath) {
  jsPath = jsPath ||'injectScript.bundle.js';vartemp =document.createElement('script');
  temp.setAttribute('type','text/javascript');// chrome-extension://mapfodeofmlldcgdgahpjiefememgeei/injectScript.bundle.jstemp.src= chrome.runtime.getURL(jsPath);
  temp.onload=function() {// 放在页面不好看,执行完后移除掉this.parentNode?.removeChild(this);
  };document.head.appendChild(temp);
}复制代码

injected 的内容需要在资源列表中进行声明:

      "web_accessible_resources":[{"resources":["injectScript.bundle.js",],"matches":["http://*/*","https://*/*","<all_urls>"]}]复制代码

例子:拦截 xhr 请求。

      // "injectScript.bundle.js"xhook.after(function(request, response) {if(request.url.match(/rest\/api.+files.+/)) {console.log(response?.data)
  }
});复制代码

3.4 background

3.4.1 概述

插件是基于事件的用来修改或增强 Chrome 浏览体验的程序。事件是浏览器触发的,例如导航到新页、删除书签或关闭选项卡。插件在 background 中监视这些事件,然后根据指定的指令进行响应。
background 一旦加载完成,只要执行某个操作(比如发起网络请求或调用 Chrome API)就会一直运行,此外,在关闭所有可见视图和所有消息端口之前,不会被卸载。

总而言之,background 为所有的视图和消息端口服务。

background 在需要的时候被加载,空闲的时候被卸载。一些事件的例子包括:

  • 插件首次安装或者更新版本;
  • backgroud 正在监听一些事件,这些事件被触发;
  • content script 或者其他扩展发送消息;
  • 插件中的其他视图调用 runtime.getBackgroundPage

3.4.2 简单例子

创建一个右键菜单。

      functioncreateContextMenus() {
  chrome.contextMenus.create({type:'normal',id:'savePage',title:'保存页面',checked:false,
  });
}
chrome.runtime.onInstalled.addListener(() =>{createContextMenus();
});复制代码

四、其他展现形式

4.1 homepage_url

插件主页,免费广告位!
image.png

      {"homepage_url":"https://km.xxxx.com", }复制代码

4.2 Options页面

4.2.1 概述

插件的配置页面。

4.2.2 配置

有两种配置方法,对应两种展现形式。

      {// 方式1"options_page":"options.html",// 方式2 优先级高"options_ui":{"page":"options.html"},}复制代码
image.png image.png

4.3 Devtools

开发者工具。

devtools1.png devtools2.png

4.4 override(覆盖特定页面)

可以将 Chrome 默认的一些特定的页面改为使用扩展提供的页面:

页面名称 url 配置 备注
新标签页 chrome://newtab "chrome_url_overrides":
{
"newtab": "newtab.html"
}
历史记录 chrome://history "chrome_url_overrides":
{
"history": "history.html"
}
书签 chrome://bookmarks "chrome_url_overrides":
{
"bookmarks": "bookmarks.html"
}

注意点:

  1. 不能替换隐身模式下的新标签页;
  2. 一个插件只能覆盖一个页面。

4.5 Omnibox

Chrome和其他浏览器相比一个最大的区别就是地址栏——其实不仅仅是地址栏,而是一个多功能的输入框,Google将其称为omnibox(中文为“多功能框”)。我们熟悉的一个功能就是用户可以直接在omnibox搜索关键字,Chrome也将omnibox开放给开发者,这使得omnibox更加强大。
image.png

五、通讯

由于 content script 运行在网页的上下文中,而不在扩展中,因此它们通常需要某种方式来与扩展的其余部分进行通信。

从浏览器插件内的视角来看通讯:
image.png

5.1 简单的一次性请求

5.1.1 从 content-scripts 发起请求

      chrome.runtime.sendMessage({greeting:"hello"},function(response) {console.log(response.farewell);
});复制代码

5.1.2 发送消息到 content-scripts

      chrome.tabs.query({active:true,currentWindow:true},function(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, {greeting:"hello"},function(response) {console.log(response.farewell);
  });
});复制代码

5.1.3 接受消息

      chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {console.log(sender.tab?"from a content script:"+ sender.tab.url:"from the extension");if(request.greeting==="hello")sendResponse({farewell:"goodbye"});
  }
);复制代码

5.2 长链接

可以使用 runtime.connecttabs.connect建立一个长链接进行通讯。

      // port1varport = chrome.runtime.connect({name:"knockknock"});
port.postMessage({joke:"Knock knock"});
port.onMessage.addListener(function(msg) {if(msg.question==="Who's there?")
    port.postMessage({answer:"Madame"});elseif(msg.question==="Madame who?")
    port.postMessage({answer:"Madame... Bovary"});
});// port2chrome.runtime.onConnect.addListener(function(port) {console.assert(port.name==="knockknock");
  port.onMessage.addListener(function(msg) {if(msg.joke==="Knock knock")
      port.postMessage({question:"Who's there?"});elseif(msg.answer==="Madame")
      port.postMessage({question:"Madame who?"});elseif(msg.answer==="Madame... Bovary")
      port.postMessage({question:"I don't get it."});
  });
});复制代码

5.3 跨插件通讯

除了在插件中的不同组件之间发送消息之外,还可以使用消息传递 API 与其他插件进行通信。
可以使用 runtime.onMessageExternalruntime.onConnectExternal来监听传入的请求和连接。
监听消息:

      // For simple requests:chrome.runtime.onMessageExternal.addListener(function(request, sender, sendResponse) {if(sender.id=== blocklistedExtension)return;// don't allow this extension accesselseif(request.getTargetData)sendResponse({targetData: targetData});elseif(request.activateLasers) {varsuccess =activateLasers();sendResponse({activateLasers: success});
    }
  });// For long-lived connections:chrome.runtime.onConnectExternal.addListener(function(port) {
  port.onMessage.addListener(function(msg) {// See other examples for sample onMessage handlers.});
});复制代码

发送消息:

      // The ID of the extension we want to talk to.varlaserExtensionId ="abcdefghijklmnoabcdefhijklmnoabc";// Make a simple request:chrome.runtime.sendMessage(laserExtensionId, {getTargetData:true},function(response) {if(targetInRange(response.targetData))
      chrome.runtime.sendMessage(laserExtensionId, {activateLasers:true});
  }
);// Start a long-running conversation:varport = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);复制代码

5.4 从网页发送信息

插件可以接收和响应来自常规网页的消息。要使用这个特性,必须在 Manifent.json 中指定要与哪些网站通信。
通讯方式和跨插件通讯方式类似。

5.5 Native通讯

Chrome 插件可以与原生应用进行通讯,原生应用可以通过注册一个 Native Messaging Host,Chrome 以一个单独的进程启动 Host,并使用标准输入和标准输出流进行通信。
详情可参考: developer.chrome.com/docs/apps/n…

六、如何查看某个插件的源码

  1. 开源的, 如 github.com/adblockplus…
  2. 本地查看
    1. 第一步:打开开发者模式,找到对应插件的id
    2. 第二步:本地插件目录,/Users/mac/Library/Application Support/Google/Chrome/Default/Extensions

七、最佳实践推荐

喜欢使用 React + TS:
github.com/chibat/chro…
github.com/lxieyang/ch…
喜欢使用 rxjs:
github.com/alibaba/bro…
不想要任何框架:
github.com/SimGus/chro…

八、适配其他浏览器

切换到 chromium 内核的浏览器适配工作还是比较小的,firefox 也支持 chrome API。

我们只需要对照各浏览器厂商提供的开发文档,关注我们用到的 API 是否有差异,有差异的部分,做一下兼容即可。

可参考各浏览器的 extension 开发文档:

firefox: developer.mozilla.org/en-US/docs/…

Edge: learn.microsoft.com/zh-cn/micro…

360: open.se.360.cn/open/extens…

搜狗: ie.sogou.com/open/doc/

九、发布

chrome开发者中心: chrome.google.com/webstore/de…

firefix发布文档: addons.mozilla.org/en-US/devel…

edge发布文档: learn.microsoft.com/zh-cn/micro…

十、未来

  • content-sctipts + Mockjs 自动填充表单?
  • UI检查,自动化测试?
  • 性能、依赖检测,Lighthouse?
  • 账号管理&一键登录?

可以在评论区说说你们用到的场景~~

参考

chrome 插件开发指南(字节跳动技术团队)
Chrome Extension 扩展程序迁移至 Manifest V3
Chromium扩展(Extension)的Content Script加载过程分析
一种开发 Chrome 扩展程序的新姿势
Message passing
Native Messaging

相关 [chrome 插件 开发] 推荐:

为豆瓣爱好者开发的 Chrome 插件:豆瓣一点

- bridge - 谷奥——探寻谷歌的奥秘
豆瓣一点这枚Chrome扩展适用于将豆瓣的电影和书籍评价作为是否入手重要依据的朋友,作者说他自己在VeryCD上看到新的电影和美剧都要到豆瓣上看看再决定下载. 作者开发这个扩展也是为了方便自己上网时随时查询,故取名“豆瓣一点”,寓意“点一下就可以豆瓣一下了”. 豆瓣搜索:在网页中选中一段文字,在豆瓣中搜索.

Chrome插件开发简单实战教程

- - Chrome迷
Chrome凭借其简单,稳定,快速的优点迅速风靡全球,占领浏览器市场,直逼IE的市场份额,超越也只是时间问题. 初次打开Chrome浏览器,你会发现整个页面只有一个地址栏,一对箭头,刷新按钮和一把扳手,当然还有最重要的空白页面,这就是Chrome的整体构造,可以说是最简单的浏览器了,但是仔细深入你会Chrome的功能远不止这些,通过Chrome的扩展中心你可以安装成千上万的插件来丰富你的浏览器功能,这时你就会发现Chrome的强大之处.

chrome 插件开发指南(Manifest V3) - 掘金

- -
严格来讲,我们正在说的东西应该叫 Chrome 扩展(Chrome Extension),真正意义上的 Chrome 插件是更底层的浏览器功能扩展,需要对浏览器源码有一定掌握才有能力去开发. 鉴于 Chrome 插件的叫法已经习惯,本文中也全部采用这种叫法. 在百度指数里也没有收录“chrome 扩展”这个词,只有“chrome 插件”.

[译]Web设计者和开发者必备的28个Chrome插件

- liu - 博客园-首页原创精华区
       对于许多Web设计者和开发者来说,Firefox浏览器是无法超越的,对于其他人Chrome正在蚕食Firefox的浏览器市场.        在过去的两年,谷歌Chrome浏览器的发布以来,引起了人们激烈争论究竟哪个浏览器更加优秀. Mozilla的开源产品经受了时间的考验和Firefox已经快速成为继微软IE浏览器后的第二大最流行的浏览器.

Chrome优秀插件推荐 — SEO必备

- yun - 就SEO
和Chrome已经是老朋友了,一直很喜欢他简洁的风格. 虽然现在插件越来越多,Chrome依然快速简洁,并且功能却愈加强大. 下面给大家介绍我做SEO时最常用的几个插件. 可以看网站PR, Alexa, WOT, IP地址以及所在的地理位置,简单但十分好用. 可以查看外链情况,页面的Meta,书签收录,域名信息,nofollow等等,很全很强大的插件.

10个提高效率的Chrome插件

- 建江 - ITeye资讯频道
  导读:Chrome浏览器是一直都热闹异常的浏览器大家庭中新成员. 虽然Google Chrome浏览器相比之下还很年轻,但优异的性能、简洁的界面以及较高的可用性使其一鸣惊人.   Chrome浏览器的另一个实用的地方是,用户可以添加插件来处理日常的网络任务. 其中许多Chrome插件可以提高用户的工作效率,并能使用户工作更轻松快捷.

Chrome插件的国际化技巧

- iBeyond - keakon的涂鸦馆
今天在查看Proxy SwitchySharp的源码时,看到了一个国际化的技巧. 觉得很不错,于是给Sync My Tabs插件增加了国际化支持,并在此分享. 其实之前我在做Chrome插件时都有个疑点,翻译JavaScript里的文字用Chrome的i18n API很容易,但是要翻译HTML就麻烦了,毕竟动态生成HTML没有静态的方便.

SocialBa! – 社交网络同步插件[Chrome]

- - 小众软件
如今登陆社交网站、发点心情、吐点槽,已经成为很多人每天必做的事情,好比吃饭,一天不吃饿得慌. 是一款 Chrome 插件,可以帮助以上人群同步几乎所有主流社交网站的心情和吐槽,包括新浪微博、腾讯微博、人人网、Google+、Facebook、Twitter、VKontakte、开心网、QQ空间、Linkedin、Plurk.

Chrome网页应用开发教程

- tiger - 互联网的那点事
发布时间:2011年2月1日. 发布源:How-Tos(OhBoard). 我花了10天时间开发了OhBorad,这个小巧的白板应用. 12月12日,我萌生了想法,12月22日我赚到了第一笔钱3.99美金. 所以在这里和大家分享一下这个开发指南. 如果你打算自己做Chrome网页应用,那么你可幸运了.

手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单

- huangct - 博客园-首页原创精华区
Chrome的更新速度可以说前无古人,现在我每天开机的第一件事就是打开Chrome检查是不是有了新版本. 界面清爽、操作人性化、网络备份资料和快速的启动速度令我爱不释手,还有它拥有众多的扩展程序,相对于firefox的插件来说,数量上和质量上稍显不足,但相信chrome将会很快在扩展上超越firefox,firefox上内存占用上实在不令人满意,也许我使用firefox的一个原因就是因为firebug,不过相信chrome平台的类firebug插件也会很快出现.