使用Chrome插件可以为Chrome浏览器带来一些功能性的扩展,进而提高使用体验;俗话说的好Chrome没插件,香味少一半,Chrome最大的优势还是其支持众多强大好用的扩展程序;今天就来了解一下插件是如何开发的,和普通的浏览器页面开发有什么区别,以及安利一些功能强大的插件。
注:本文为开发教程为chrome插件,后面为自己开发的二维码短链插件,有需要可以私信
浏览器插件种类
常见的浏览器插件种类可以分为以下几种类型:
-
以chromium为内核的浏览器插件,如chrome、edge、opera
-
firefox浏览器插件
-
safari浏览器插件
本次只专注于以chromium为内核的浏览器插件,因为这类浏览器使用最为广泛。
Chrome插件简介
Chrome插件,官方名称extensions(扩展程序);为了方便理解,以下都称为Chrome插件,或者简称插件,那么什么是Chrome插件呢?
扩展程序是自定义浏览体验的小型软件程序。它们让用户可以通过多种方式定制
Chrome
的功能和行为。
插件程序可以提供以下几个功能:
-
生产力工具:
-
网页内容丰富
-
信息聚合
-
乐趣和游戏
可以通过点击更多 -> 扩展程序
来查看所有安装的插件,或者直接打开插件标签页chrome://extensions/。
获取插件
-
大多数Chrome用户从Chrome网上应用店获得插件程序。世界各地的开发人员会在Chrome网上应用店中发布他们的插件,经过Chrome的审查并向最终用户提供。
-
但是官方渠道需要翻墙,下面分享国内版本以及超实用插件
优秀/实用插件分享
国内插件渠道
-
扩展迷:https://extfans.com/
官方插件(站外)
-
https://chromewebstore.google.com/
AdGuard 广告拦截器
-
chrome应用商店渠道
-
扩展迷渠道
还可以自定义拦截某个区域
FeHelper前端助手
-
扩展迷渠道
-
chrome应用商店渠道
FE助手是由国人开发的一款前端工具集合的小插件,插件功能比较全面:包括字符串编解码、代码压缩、美化、JSON格式化、正则表达式、时间转换工具、二维码生成与解码、编码规范检测、页面性能检测、页面取色、页面截屏、Ajax接口调试。
-
右击即可触发
Octotree
-
扩展迷渠道
-
chrome应用商店渠道
在Github上查看源代码的体验十分糟糕,尤其是从一个目录跳转到另一个目录的时候,非常麻烦。Octotree是一款chrome插件,用于将Github项目代码以树形格式展示,而且在展示的列表中,我们可以下载指定的文件,而不需要下载整个项目。
Allow CORS
-
扩展迷渠道
-
chrome应用商店渠道
我们开发过程中经常会遇到接口跨域的问题,通过Allow CORS: Access-Control-Allow-Origin这个插件,可以允许我们在接口的响应头轻松执行跨域请求,只需要激活插件并且执行。
沉浸式翻译
-
扩展迷渠道
-
chrome应用商店渠道
可以中英对照全篇翻译、pdf翻译
Tampermonkey(油猴)
-
扩展迷渠道
-
chrome应用商店渠道
Tampermonkey(俗称油猴)是一款免费的浏览器扩展和最为流行的用户脚本管理器。虽然有些受支持的浏览器拥有原生的用户脚本支持,但 Tampermonkey将在您的用户脚本管理方面提供更多的便利。 它提供了诸如便捷脚本安装、自动更新检查、标签中的脚本运行状况速览、内置的编辑器等众多功能, 同时Tampermonkey还有可能正常运行原本并不兼容的脚本。
通过给管理器安装各类脚本,可以让大部分 HTML 为主的网页更方便易用,比如:全速下载网盘文件、视频会员网站去广告、悬停显示大图、Flash/HTML5 播放器转换、阅读模式等。有点像给Chrome的插件装上插件(这里又是一个套娃)。
油猴如何使用(视频会员为例)
插件如何工作?
-
插件是基于Web技术构建的,例如HTML、JavaScript和CSS。它们在单独的沙盒执行环境中运行并与Chrome浏览器进行交互。
-
插件允许我们通过使用API修改浏览器行为和访问Web内容来扩展和增强浏览器的功能。插件通过最终用户UI和开发人员API进行操作:
-
扩展用户界面,这为用户提供了一种一致的方式来管理他们的扩展。
-
扩展的API允许浏览器本身的扩展的代码访问功能:激活标签,修改网络请求等等。
-
-
要创建插件程序,我们需要组合构成插件程序的一些资源清单,例如JS文件和HTML文件、图像等。对于开发和测试,可以使用扩展开发者模式将这些“解压”加载到Chrome中。如果我们对自己开发出来的插件程序感到满意,就可以通过网上商店将其打包并分享给其他的用户。
插件的原则
我们编写的插件想要发布到Chrome网上应用店
中,就必须遵守网上应用店政策,它规定了以下几点:
-
插件必须满足一个定义狭窄且易于理解的单一目的。单个插件可以包含多个组件和一系列功能,只要一切都有助于实现一个共同的目的。
-
用户界面应该是最小的并且有意图。它们的范围可以从简单的图标到打开一个带有表单的新窗口。
如何写一个简易的浏览器插件
开发浏览器的前置要求
开发浏览器插件对开发者最基础要求为能够使用html、css、javascript。如果想要进一步学习如何使用框架开发的话需要开发者熟悉react开发。
Chrome 插件由不同的部件构造而成,包括:后台脚本、内容脚本、选项页、UI 元素以及各种逻辑文件。
参考文档:
-
chrome官方插件开发教程(v3版本)
-
框架进阶开发浏览器插件
项目目录结构
manifest.json
所有的浏览器插件必须在根目录下新建文件manifest.json
清单记录重要的元数据,定义资源,声明权限,并标识哪些文件在后台和页面上运行。这是插件的配置文件,说明了插件的各种信息;它的作用等同于小程序的app.json和前端项目的package.json。
service worker
service worker
作用是处理和监听浏览器事件,相当于是在后台持续运行的脚本,可以使用浏览器的全部api;但是不能和页面内容直接交互。
content scripts
content scripts
是在网页上执行的javascript,可以读取和修改网页上的dom元素,但只能使用部分的浏览器api,具体请见:content scripts。
插件页面
插件页面包括浏览器的图标以及其点击后的效果,如popup页面;options页面,也就是右键浏览器图标之后点击选项
弹出的页面;其他页面,也就是除了上述两种页面的其他浏览器插件的页面。
所有的插件页面都可以使用浏览器api。
manifest.json
具体配置请参考文档manifest
manifest.json常用的配置如下:
{
// 必须的
"manifest_version": 3,
"name": "插件名称",
"version": "版本",
// 常用
"description": "插件描述",
"author": "作者名",
"background": { // 配置service worker
"service_worker": "background.js"
},
"options_ui": { // 配置options页面
"page": "options.html",
"open_in_tab": true
},
"content_scripts": [ // 配置content scripts
{
"matches": [
"*://www.baidu.com/*"
],
"js": [
"test.js"
],
"all_frames": true,
"css": []
}
],
"web_accessible_resources": [ // 配置Web可访问资源
{
"matches": [
"*://www.baidu.com/*"
],
"resources": [
"test.css"
]
}
],
"host_permissions": [ // 与主机权限相关,推荐使用同样的设置
"https://*/*"
],
"permissions": [ // 配置插件所使用的api权限
"storage",
"contextMenus",
"cookies"
],
"action": { // 使用action api配置插件工具栏中图标、弹出页面等内容
"default_icon": {
"16": "icon16.png",
"32": "icon32.png",
"48": "icon48.png",
"64": "icon64.png",
"128": "icon128.png"
},
"default_popup": "popup.html",
"icons": {
"16": "icon16.png",
"32": "icon32.png",
"48": "icon48.png",
"64": "icon64.png",
"128": "icon128.png"
}
}
}
-
我们在项目中创建一个最简单的
manifest.json
配置文件,manifest 描述插件的元数据,包括插件名、描述以及版本等等:
{
// 插件名称
"name": "一个简单的插件",
// 插件的描述
"description" : "Demo Extension to change background color!",
// 插件的版本
"version": "1.0",
// 配置插件程序的版本号,最新是3
"manifest_version": 3
}
加载未打包插件
为方便插件调试,Chrome在开发模式下,支持加载未打包的插件。只需指定插件的开发目录(包含manifest)即可完成加载,关键步骤如下:
-
打开插件管理页面,直接点这个访问这个链接即可:chrome://extensions;
-
-
或者从菜单进入设置页,找到并点击扩展程序;
-
亦或从菜单移到更多工具,找到并点击扩展程序;
-
-
点击位于右上角的开发模式开关,开启开发模式;
-
点击左上角的加载已解压的扩展程序,然后直接选择插件目录即可;
插件安装成功!虽然它现在还什么都干不了,但总算迈出了第一步。由于还没在 manifest 配置文件里注册图标,Chrome 会为插件显示默认图标。
添加简单功能
插件虽已安装,却啥也没干,因为还没添加执行逻辑。我们先写一些代码,让插件保存背景颜色值。
注册后台执行脚本
跟其他重要部件一样,后台脚本也必须注册到 manifest 配置文件。在 manifest 注册后台脚本,相当于告诉插件去哪找后台脚本,以及脚本应该执行什么事情。
Service Worker
{
"name": "一个简单的插件",
"description": "Demo Extension to change background color!",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js",
// 开启模块化
"type": "module"
}
}
在 manifest 加上 background 配置后,Chrome 现在知道插件包含一个 服务执行器( service worker )。当你重新加载插件时,Chrome 会找到注册的后台脚本,执行其中的额外指令,比如监听一些重要事件。
编写后台脚本
在插件目录创建 background.js 文件,并写上代码:
const color = "#3aa757";
chrome.runtime.onInstalled.addListener(() => {
console.log("插件已被安装");
chrome.storage.sync.set({ color });
console.log(`[Coloring] default background color is set to: ${color}`);
});
这段代码通过常量定义默认的背景色,然后通过 Chrome API 注册 onInstalled 事件监听函数。监听函数将在插件安装的时候执行,调用 storage 存储接口,保存默认的背景色。
之所以用 storage 来保存背景色,是为了能够在不同的部件中访问或者更新它。
现在点击插件右下角的转圈,重新加载插件,但我们发现插件报错了。因为插件使用了 storage 接口,但还没获得 Chrome 的授权。
调试后台脚本
点击重新加载插件后,插件卡片会显示查看视图新字段,包含一个可以点击的链接Service Worker。点击该链接,即可打开对应后台脚本的调试终端,从中可以查到报错细节:
由此可见,chrome.storage 是 undefined ,因为 Chrome 还没将 storage 接口授权给插件。
storage存储接口授权
我们在插件安装时在storage中设置一个值,这将允许多个插件组件访问该值并进行更新操作。大部分接口,包括 storage 接口,必须注册在 manifest 配置文件 permissions 字段下,获得授权之后才能使用:
{
"name": "一个简单的插件",
"description": "Demo Extension to change background color!",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
// 授权
"permissions": ["storage"]
}
重新加载插件,可以看到 background.js 执行无误,并如预期那样输出日志
弹窗操作以及选项界面
Chrome 插件可能使用各种形式的用户界面,我们先试试 Popup 弹出窗口。在插件目录创建一个名为 popup.html
的文件,在创建个button.css:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="button.css">
</head>
<body>
<button id="changeColor">1233</button>
</body>
</html>
options.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
Options Page
</body>
</html>
button {
height: 30px;
width: 60px;
outline: none;
margin: 10px;
border: none;
background: #ff6700;
border-radius: 2px;
}
button.current {
box-shadow: 0 0 0 2px white, 0 0 0 4px black;
}
Chrome 插件用户界面也是用 HTML 来编写,前端工程师应该再熟悉不过了。
跟后台脚本一样,用户界面文件也要在 manifest 中注册后,才能被 Chrome 识别。我们在 manifest 中添加一个 action 对象,并将 popup.html 文件作为 default_popup 属性注册进去:
{
"name": "一个简单的插件",
"description": "Demo Extension to change background color!",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html" // 配置弹窗操作界面
},
"options_ui": {
"page": "options.html", // 选项
"open_in_tab": true
}
}
效果如图:
配置icon图标
配置扩展程序图标
制作插件:在线Chrome插件图标生成器 - UU在线工具
{
"name": "一个简单的插件",
"description": "Demo Extension to change background color!",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"permissions": ["storage"],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "image/icon16.gif",
"32": "image/icon32.gif",
"48": "image/icon48.gif",
"128": "image/icon128.gif"
}
},
"icons": {
"16": "image/icon16.gif",
"32": "image/icon32.gif",
"48": "image/icon48.gif",
"128": "image/icon128.gif"
}
}
案例:
chrome-plugin-base.zip
content scripts
参考文档content scripts
content scripts运行拓展将逻辑注入页面
api权限
content scripts只能使用部分的浏览器api,最常用的api为storage与runtime两个api。
具体请参考content scripts可使的api
所以在进行一些特定操作时需要通过runtime.sendMessage
向service worker发送信息来执行某些操作
运行环境
content scripts存在于一个孤立的环境中,允许内容脚本对其 JavaScript 环境进行更改,而不会与页面或其他扩展的content scripts发生冲突。
比如content scripts的变量对于主机页面和其他插件的content scripts是不可见的;又或者通过content scripts改写了页面的某个api,而页面原本的元素在触发这个api时并没有按照预期的效果执行,其原因就是content scripts修改的只是自身环境的api,而不是原页面的api。
注入方式
注入方式分两种:静态注入和动态注入
静态注入
在manifest.json
中配置的脚本即为静态注入,在匹配的页面上自动注入脚本。
{
"name": "test",
...
"content_scripts": [
{
"matches": ["https://*.test.com/*"],
"css": ["styles.css"],
"js": ["content-script.js"]
}
],
...
}
配置项 | 详情 | |
matches | 指定此内容脚本将被注入到哪些页面,详见match_patterns | |
js | 要注入匹配页面的 JavaScript 文件列表。它们按照它们在此数组中出现的顺序注入(比如后者依赖前者,就得按顺序引入)。 | |
css | 要注入匹配页面的 CSS 文件列表。在为页面构造或显示任何 DOM 之前,它们按照它们在此数组中出现的顺序注入。 | |
all_frames | 默认为 | |
run_at | document_idle | 参考:运行 |
document_start | ||
document_end |
动态注入
使用chrome.scripting.executeScript
进行动态注入
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
world: "MAIN",
files: ['content-script.js']
});
});
动态注入的脚本可以通过设置world
属性为MAIN
直接进入网页文档,而不是独立的环境。这时在主页面就可以访问到脚本的变量等信息
如果想要主动将脚本注入主页面,可以在background
监听页面进行注入;或者在静态注入的脚本中动态插入script
标签并且将src
设置为想要注入主页面的脚本的url。
案例:
向百度注入一些脚本:
content-scripts.zip
UI elements
参考文档UI elements
该内容主要是针对于插件在工具栏的图标所展开。由于内容太多,这里只粗略介绍有哪些常用功能。
指定工具栏图标
在manifest.json的action配置项配置图标
{
"name": "My Extension",
...
"action": {
"default_icon": {
"16": "image_16.png",
"32": "image_32.png",
"48": "image_48.png",
"128": "image_128.png"
}
}
...
}
Action badge
在图标右下角可以显示一些内容,最多展示四个字符,效果如下图:
chrome.action.setBadgeText({text: 'ON'}); // 配置文本
chrome.action.setBadgeBackgroundColor({color: '#4688F1'}); // 配置背景颜色
popup页面
弹出窗口是一个 HTML 文件,当用户单击操作图标时,它会显示在一个特殊的窗口中。弹出窗口的工作方式与网页非常相似;它可以包含指向样式表和脚本标签的链接,但不允许内联 JavaScript。
{
"name": "Drink Water Event",
...
"action": {
"default_popup": "popup.html"
}
...
}
弹出窗口也可以通过调用动态设置action.setPopup。
chrome.storage.local.get('signed_in', (data) => {
if (data.signed_in) {
chrome.action.setPopup({popup: 'popup.html'});
} else {
chrome.action.setPopup({popup: 'popup_sign_in.html'});
}
});
Tooltip
将鼠标悬停在操作图标上时,使用工具提示向用户提供简短说明或说明。默认情况下,提示会显示扩展的名称。
可以通过default_title
设置。
{
"name": "Tab Flipper",
...
"action": {
"default_title": "default_title"
}
...
}
也可以通过action.setTitle设置。
图标点击事件
chrome.action.onClicked.addListener(function(tab) {
chrome.action.setTitle({tabId: tab.id, title: "You are on tab:" + tab.id});
});
Omnibox
用户可以通过Omnibox API调用扩展功能。在清单中包含该"omnibox"字段并指定关键字。多功能框新标签搜索示例:tt
用作关键字。
chrome.omnibox.onInputEntered.addListener((text) => {
// Encode user input for special characters , / ? : @ & = + $ #
const newURL = 'https://www.google.com/search?q=' + encodeURIComponent(text);
chrome.tabs.create({ url: newURL });
});
{
"manifest_version": 3,
"name": "My Extension",
"version": "0.0.1",
"description": "插件描述",
"author": "gaolu",
"background": {
"service_worker": "background.js"
},
"host_permissions": [
"https://*/*"
],
"omnibox": { "keyword" : "tt" }
}
Context menu
可以通过在清单中授予权限来使用ContextMenus API 。
{
"permissions": [
"contextMenus",
"storage"
]
}
contextMenus.create()通过调用后台脚本创建上下文菜单。这应该在runtime.onInstalled侦听器事件下完成。
Notifications
您可以通过直接在用户的系统托盘中显示通知来向用户传达相关信息。
要使用notifications API,您必须在清单中声明权限notifications
。
{
"permissions": [
"notifications",
],
}
浏览器 api
插件除了使用网页的web api外,也可以使用浏览器的api
api文档:chrome api
大多数的api都是异步的,所以使用其返回的结果有两种方式:
-
通过回调函数
-
通过异步操作(推荐)
// Promise
chrome.tabs.query(queryOptions)
.then((tabs) => {
chrome.tabs.update(tabs[0].id, {url: newUrl});
someOtherFunction();
});
// async-await
async function queryTab() {
let tabs = await chrome.tabs.query(queryOptions);
chrome.tabs.update(tabs[0].id, {url: newUrl});
someOtherFunction();
}
// callback
chrome.tabs.query(object queryInfo, function callback)
有些api的应用需要在manifest
的permissions
字段设置对应权限
通信
文档: https://developer.chrome.com/docs/extensions/mv3/messaging/
由于content_scripts运行在网页中,而不是浏览器插件的环境,所以它需要一些特殊的方式来和浏览器插件的内容进行通信。
通信的方式包括用于一次性请求的简单通信和用于长期连接的长连接通信。
简单通信
简单通信可以使用runtime.sendMessage()或tabs.sendMessage()与插件的其他部分进行通信。
上述api可以将json字段从content_scripts发送给插件,当然也可以从插件将信息发送给content_scripts。如果要处理返回的数据,需要使用返回的Promise;也可以设置回调函数。
从content_scripts发送请求:
(async () => {
const response = await chrome.runtime.sendMessage({
data: 'hello',
});
console.log(response);
})();
接收信息
在事件接收端需要设置一个runtime.onMessage事件侦听器来处理消息。
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log(request, sender);
if (request.greeting === "hello") {
sendResponse({farewell: "goodbye"});
}
});
需要注意的是:sendResponse是同步调用的,如果想要在异步调用需要在onMessage
的事件处理函数中添加return true;
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
// console.log(request, sender);
(async () => {
if (request.greeting === "hello") {
const data = await getData();
sendResponse(data);
}
})();
return true;
});
如果多个页面侦听onMessage事件,则只有第一个调用sendResponse()特定事件的页面才能成功发送响应。其他对该事件的所有其他响应事件将被忽略。
长连接通信
某些情况下需要持续事件更长的通信,这时可以使用长连接通信,分别使用runtime.connect或tabs.connect打开一个从content_scripts到插件的长期通道或插件到content_scripts的长期通道。
建立连接
建立连接时,每一端都会获得一个runtime.Port对象,用于发送和接收消息。
const port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener((msg) => {
if (msg.question === "Who's there?")
port.postMessage({answer: "Madame"});
else if (msg.question === "Madame who?")
port.postMessage({answer: "Madame... Bovary"});
});
从插件向content_scripts发送请求是类似的,只需要指定要连接到哪个选项卡。只需将上例中的连接调用替换为tabs.connect()即可。
处理连接信息
需要设置一个runtime.onConnect()事件侦听器。当插件的另一部分调用connect()
时,将触发此事件,其中回调函数的参数是用来通过连接发送和接收消息的runtime.Port对象
chrome.runtime.onConnect.addListener((port) => {
console.assert(port.name === "knockknock");
port.onMessage.addListener((msg) => {
if (msg.joke === "Knock knock")
port.postMessage({question: "Who's there?"});
else if (msg.answer === "Madame")
port.postMessage({question: "Madame who?"});
else if (msg.answer === "Madame... Bovary")
port.postMessage({question: "I don't get it."});
});
});
案例:
message.zip
浏览器插件Storage
与网页类似,浏览器插件也有用来储存数据的空间:我们可以调用浏览器插件的storage api,以此来持久化用户数据和状态。
关于浏览器插件储存有一些特性:
-
浏览器的所有页面(包括service worker、content script)都可以使用storage api
-
读取和写入是异步的
-
用户清除缓存和历史记录,数据也不会收到影响
储存区域
浏览器插件的storage api有localStorage和sessionStorage两个区域,用于储存不同用途的数据。插件的storage api也有不同的储存区域;常用的storage区域为:
-
local:本地储存,卸载插件时会清除,储存上限为5MB
-
sync:如果用户启用的账号同步功能,储存的数据会同步到用户登录的任何chrome浏览器中。如果用户禁用了同步,则该api功能与local类似。储存上限为100KB,每一条的上限是8KB,最多能存512条数据。并且一段时间内最大写入数也有限制,具体详见sync限制。可以用于储存一些需要跨浏览器储存的数据。
-
session:在浏览器运行期间会将数据存储在内存中,默认情况下不会将数据暴露给content script,但可以通过调用chrome.storage.session.setAccessLevel() api,让content script可以访问到storage.session中的数据。储存上限为10MB,可以用他来存一些临时的全局变量
使用storage api
想要使用storage api
首先要在manifest
的permissions
字段中配置:
{
"name": "My extension",
...
"permissions": [
"storage"
],
...
}
local:
chrome.storage.local.set({ key: value }).then(() => {
console.log("Value is set");
});
chrome.storage.local.get(["key"]).then((result) => {
console.log("Value currently is " + result.key);
});
sync:
chrome.storage.sync.set({ key: value }).then(() => {
console.log("Value is set");
});
chrome.storage.sync.get(["key"]).then((result) => {
console.log("Value currently is " + result.key);
});
session:
chrome.storage.session.set({ key: value }).then(() => {
console.log("Value was set");
});
chrome.storage.session.get(["key"]).then((result) => {
console.log("Value currently is " + result.key);
});
监听储存变化
使用chrome.storage.onChanged.addListener
添加监听的回调函数
chrome.storage.onChanged.addListener((changes, namespace) => {
for (let [key, { oldValue, newValue }] of Object.entries(changes)) {
console.log(
`Storage key "${key}" in namespace "${namespace}" changed.`,
`Old value was "${oldValue}", new value is "${newValue}".`
);
}
});
插件架构
一个浏览器插件主要是由五部分组成
-
manifest:插件配置文件
-
content_script:注入到浏览器页面的脚本
-
service_worker:插件自己的后台脚本
-
extension page:插件的各个页面,比如popup、options、devtools、sidepanel
-
browser api:可以通过api调用浏览器的功能(存储、历史记录、通信等)
-
首先manifest是一个json文件,配置了插件的信息,其余部分的内容都需要在这里配置(当然也可以在service_worker中动态配置);需要放在插件的根目录下
-
browser api是插件与浏览器交互的通道;根据浏览器不同,可能有些差异,但大部分的api是一致的
-
content_script是注入到浏览器页面的脚本,可以实现修改页面的dom,获取页面元素等操作。他能使用的browser api是有限的,想实现一些功能需要与service_worker或者extension page通信,由这两部分的代码代为执行一些操作。
-
service_worker相当于是插件的后端,也就是一个在后台运行的脚本,能够访问到所有的browser api。控制浏览器的操作都可以在这里运行
-
extension page是插件内部的一些页面。有一些页面是插件规定的,比如popup、options、devtools、sidePanel等;还有一些页面是插件自定义的页面,可以通过browser api打开这些页面。在extension page也可以使用所有的browser api
数据流
-
浏览器插件的通信是注入到网页的脚本(content_script)与插件(service_worker和extension page)使用browser api传递数据。
-
插件向脚本发送信息需要知道对应脚本所在标签页的id,才可以发送信息,并且获得脚本返回的响应
-
而脚本向插件发送信息则可以直接发送,并获取插件返回的响应
开发生成二维码插件
背景
开发移动端的同学往往需要多个设备来会测试,市面上的二维码生成对于长链接生成的二维码密度过于密集,所以想实现一个可以生成短链的插件,帮助我们能直接访问链接或者文本。
需要实现的功能
前端插件:
生成二维码/生成短链接
服务端功能:
-
根据浏览器指纹- 生成动态短链(10分钟有效)
-
定时10分钟删除短链数据
-
短链响应二维码内容,如果是链接那就302,如果不是直接body展示
已实现效果:
点击插件会自动生成当前页面的二维码,也可以手动生成二维码,如果觉得二维码生成的密度太大,可以点击生成短链,可以生成一个固定短链的二维码(10分钟内可保存本地,不管替换成什么链接都可用这个二维码)