Skip to content
鼓励作者:欢迎打赏犒劳

02-谷歌插件开发

教程:https://developer.mozilla.org/zh-CN/docs/Mozilla/Add-ons/WebExtensions

官方教程:https://developer.chrome.com/docs/extensions/mv2/architecture-overview?hl=zh-cn

谷歌商店:https://chromewebstore.google.com/

扩展程序:chrome://extensions/

优秀博客:https://xieyufei.com/2021/11/09/Chrome-Plugin.html

https://juejin.cn/post/7231704360668020794

https://github.com/coder-lzh/chrome-plugin-demo

插件构成

chrome 插件通常由以下几部分组成:

manifest.json:相当于插件的 meta 信息,包含插件的名称、版本号、图标、脚本文件名称等,这个文件是每个插件都必须提供的,其他几部分都是可选的。

background script:可以调用全部的 chrome 插件 API,实现跨域请求、网页截屏、弹出 chrome 通知消息等功能。相当于在一个隐藏的浏览器页面内默默运行。

功能页面:包括点击插件图标弹出的页面(简称 popup)、插件的配置页面(简称 options)。

content script:早期也被称为 injected script,是插件注入到页面的脚本,但是不会体现在页面 DOM 结构里。content script 可以操作 DOM,但是它和页面其他的脚本是隔离的,访问不到其他脚本定义的变量、函数等,相当于运行在单独的沙盒里。content script 可以调用有限的 chrome 插件 API,网络请求收到同源策略限制。

插件的架构可以参考:https://developer.chrome.com/docs/extensions/mv2/architecture-overview/

重点说明以下几点:

browser action 和 page action:这俩我们可以理解为插件的按钮。browser action 会固定在 chrome 的工具栏。 而 page action 可以设置特定的网页才显示图标,在地址栏的右端,如下图: google-plugins 大部分插件点击之后会显示 UI,也就是上文描述的插件功能页面部分,一般称为 popup 页面,如下图: google-plugins popup 无法通过程序打开,只能由用户点击打开。点击 popup 之外的区域会导致 popup 收起。

page action 和 browser action 分别由 manifest.json 的 page_action 和 browser_action 字段配置。

由于 content script 受到同源策略的限制,所以一般网络请求都交给 background script 处理。

content script、插件功能页面、background script 之间的通信架构如下图:

google-plugins

创建自己的第一个谷歌插件

新建文件夹,命名CE-Demo,增加一个manifest.json的文件,内容如下:

json
{
  "name": "CE-Demo",
  "description": "CE-Demo's description shows here!",
  "version": "0.0.1",
  "manifest_version": 3
}

该文件描述了插件的基本属性信息、代码的运行路径等。后面我会不断地丰富其内容。

加载插件 这里我们直接载入整个目录(尚未打包):

地址栏输入chrome://extensions进入插件管理页面。 选中界面右上角的开发者模式 点击左上角的加载已解压的扩展程序,并选中刚才的插件文件夹 google-plugins

可以点击扩展程序按钮,鼠标移动到插件右侧的固定按钮,固定到标签栏里。 google-plugins

插件不会热更新,记得每次修改代码后点击刷新icon载入最新代码

好了,这样就安装好了我们自己的一个谷歌插件,只不过这个插件什么功能都没有。下面我们需要一点一点加功能。

注册 background.js

它是一种后台脚本,浏览器会在插件安装或重新加载时扫描它并初始化(事件的监听等)。它是整个插件的重要组成部分。必须在manifest里配置。

json
{
"name": "CE-Demo",
  "description": "I am a demo",
  "version": "0.0.1",
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js",
    "persistent": true
  }
}

persistent属性定义了插件常驻后台的方式;当其值为true时,表示插件将一直在后台运行,无论其是否正在工作; 当其值为false时,表示插件在后台按需运行,这就是Chrome后来提出的Event Page(非持久性后台)。 Event Page是基于事件驱动运行的,只有在事件发生的时候才可以访问;这样做的目的是为了能够有效减小插件对内存的消耗, 如非必要,请将persistent设置为false。 persistent属性的默认值为true

同时在插件目录添加background.js文件,包含以下代码:

当脚本安装成功的时候,就会执行下面这个事件

js
chrome.runtime.onInstalled.addListener(() => {
  console.log('后台脚本运行成功!')
});

添加popup弹框页面

popup如果要写js逻辑的话,必须要采用新建js,然后引入的方式来写!!!

popup页面是你点击工具栏的图标的时候,展示的弹窗。 google-plugins 我们需要覆盖默认的popup界面,修改manifest:

json
{
  ...
  "action": {
    "default_popup": "popup.html"
  },
  ...
}

popup.html

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div style="width: 200px;height: 100px">
        我是popup弹窗
    </div>
</body>
</html>

内容脚本 Content Scripts

插件提供了内容脚本 Content Scripts(CS)的概念,当用户打开并访问某个网站时,浏览器将CS注入网站的文档里执行。

因此,我们需在CS脚本里编写记录的逻辑。

往manifest里添加CS:

json
{
    // 在此处使用数组往页面中引入JS或者CSS。
    "content_scripts":
    [
        {
            // 当matches返回true时才会注入
            // 比如 ["http://foo.com/bar/*", "https://foobar.com/bar/*"]
            // 表示在foobar.com下的bar路径下会发生注入
            // 一个特殊的值: "<all_urls>" 表示匹配所有地址   *://*/* 也是同样的效果
            "matches": ["<all_urls>"],
            // 多个JS会按照配置的顺序引入到页面
            "js": ["content/index.js", "content/index2.js"],
            // 多个CSS会按照配置的顺序引入到页面
            "css": ["foo/bar.css"],
            // 在什么时机引入到页面, 默认document_idle。 三个可选择的值: "document_start"、"document_end"、"document_idle"
            "run_at": "document_idle",
            // 是否运行在页面所有的frame中
            "all_frames": true
        },
        {
            // 因为是数组,所以可以配置多项
        }
    ],
}
  1. *://*/* 表示 匹配全部的url
  2. document_start:所有css加载完毕,但DOM尚未创建时
  3. document_end:DOM创建完成,但图片及frame等子资源尚未加载时
  4. document_idle:document_end之后,window.onload之前

设置图标

插件在工具栏上显示的图标,也由 action 对象指定,具体为 default_icon 字段。插件在管理页面、权限警示框等场景也会显示图标,可以通过 manifest 配置 icons 字段指定

json
{
  "action": {
      "default_popup": "popup.html",
      "default_icon": {
        "16": "images/icon16.png",
        "32": "images/icon32.png",
        "48": "images/icon48.png",
        "128": "images/icon128.png"
      }
    },
    "icons": {
      "16": "images/icon16.png",
      "32": "images/icon32.png",
      "48": "images/icon48.png",
      "128": "images/icon128.png"
    }
}

右键菜单

方法一

这种写法的一级菜单默认就是插件的名字 google-plugins

manifest.json

json
{
  "permissions": ["contextMenus"]
}

background.js

js
const menuList = [
    {
        id: 'element-plus',
        title: 'element-plus',
        onclick: function () {
            chrome.tabs.create({
                url: 'https://element-plus.gitee.io/zh-CN/component/table-v2.html',
            });
        },
    },
    {
        id: 'vue-api',
        title: 'vue-api',
        onclick: function () {
            chrome.tabs.create({
                url: 'https://cn.vuejs.org/api/',
            });
        },
    },
];
// 批量创建菜单
chrome.runtime.onInstalled.addListener(function () {
    menuList.forEach((item) => {
        chrome.contextMenus.create({
            id: item.id,
            title: item.title,
            contexts: ['page'],
        });
    });
});
// 实现点击事件监听
chrome.contextMenus.onClicked.addListener(function (info, tab) {
    let selectItem = menuList.filter((item) => item.id === info.menuItemId)[0];
    if (selectItem) {
        selectItem.onclick(info, tab);
    }
});

方法二

这种写法,可以自定义一级菜单 google-plugins

js
chrome.contextMenus.create({
  title: '右键快捷菜单', //菜单的名称
  id: '10', //一级菜单的id
  contexts: ['page'], // 选中文字时用:selection
});

chrome.contextMenus.create({
  title: '百度', //菜单的名称
  id: '1101', //二级菜单的id
  parentId: '10', //父级id
  contexts: ['page'],
});

chrome.contextMenus.create 函数创建的参数解释

text
【参数】
createProperties ( object )
	type ( optional enumerated string ["normal", "checkbox", "radio", "separator"] )
		右键菜单项的类型。默认为“normal”。
	title ( optional string )
		右键菜单项的显示文字;除非为“separator”类型,否则此参数是必须的。如果类型为“selection”,您可以在字符串中使用%s显示选定的文本。例如,如果参数的值为 "Translate '%s' to Pig Latin",而用户还选中了文本“cool”,那么显示在菜单中的将会是 "Translate 'cool' to Pig Latin"。
	checked ( optional boolean )
		Checkbox或者radio的初始状态:true代表选中,false代表未选中。在给定的radio中只能有一个处于选中状态。
	contexts ( optional array of string ["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio"] )
		右键菜单项将会在这个列表指定的上下文类型中显示。默认为“page”。
	onclick ( optional function )
		当菜单项被点击时触发的函数。
		【参数】
		info ( OnClickData )
			右键菜单项被点击时相关的上下文信息。
		tab ( Tab )
			右键菜单项被点击时,当前标签的详细信息。
	parentId ( optional integer )
		右键菜单项的父菜单项ID。指定父菜单项将会使此菜单项成为父菜单项的子菜单。
	documentUrlPatterns ( optional array of string )
		这使得右键菜单只在匹配此模式的url页面上生效(这个对框架也适用)。详细的匹配格式见:模式匹配页面。
	targetUrlPatterns ( optional array of string )
		类似于documentUrlPatterns,但是您可以针对img/audio/video标签的src属性和anchor标签的href做过滤。
	enabled ( optional boolean )
		启用或者禁用此菜单项,启用为true,禁用为false。默认为true。
callback ( optional function )
	在创建完菜单项后触发。如果创建过程中有错误产生,其详细信息在Chrome.extension.lastError中。

插件右键菜单点击插件名跳转主页设置

google-plugins

json
{
  "name": "CE-Demo",
  "homepage_url": "https://blog.share888.top/"
}

如有转载或 CV 的请标注本站原文地址