调试插件的时候遇到了这个提示,了解之后得知MV2版本的chrome插件在2023年停止支持。所以在此写下MV3版本的简单教程
首先新建一个文件夹,并创建一个名为manifest.json的配置文件
{
"manifest_version":3,
"name":"这是插件名称",
"version":"0.0.1",
"description":"这是插件描述",
"action":{
"default_title":"这是鼠标移上去时提示文字"
},
"icons":{//这是插件各个尺寸的图标,可以在manifest.json同级文件夹下创建img将图标放入
"16":"img/test.png",
"32":"img/test.png",
"48":"img/test.png",
"128":"img/test.png"
}
}
然后在chrome地址栏中输入chrome://extensions/
打开右上角的开发者模式之后可以在左上角找到加载已解压的扩展程序。打开刚刚创建的文件夹
这样一个最简单的插件就完成了,但是它什么都做不了。
在主文件夹(manifest.json同级文件夹)中新建一个popup.html
文件,并在manifest.json中的action
配置popup的路径
"action":{
"default_title":"Chrome插件",
"default_popup":"popup.html"//同级文件夹下的路径
}
和一般的html一样,它也支持css和js。
DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="css/popup.css" />
head>
<body>
<div class="btn">
测试<input id="TEST" class="checkbtn" type="checkbox" />
div>
body>
<script src="js/jquery.js">script>
<script src="js/popup.js">script>
html>
在主文件夹中新建css和js用于存放对应的文件,并新建popup.css。
/* popup.css */
.btn{
width: 100px;
height: 30px;
font-size: large;
}
重载插件,在右上角处点击插件图标可以看到刚刚加入的popup.html(用户界面)
在主文件夹下的js目录新建一个popup.js,再找个jquery也放进去。
//popup.js
$(".checkbtn").click(function(){
alert($(this).attr('id'));
});
勾选checkbox之后再次打开会发现checkbox还原了,这意味着popup每次打开都会重置,并不会记录用户在用户界面上做出的改变,所以需要一个本地存储来保存popup做出的改变,在用户界面打开时还原popup的内容
在manifest.json中加入service_worker
的配置路径和本地存储权限
"background":{
"service_worker":"background.js"
},
"permissions":["storage"]
service_worker非常特殊,这是一直伴随插件运行的后台脚本,它没有前端页面,不支持dom,所以没法引入jquey和其他js,所有需要保持运行的脚本都要直接写在background.js里,同样他也不支持
XMLHttpRequest
,因此需要使用fetch来代替xhr请求。
background.js要放在主文件夹根目录,否则在使用过程中会出现service worker (无效)
的提示
//background.js
chrome.runtime.onInstalled.addListener(() => {
DBdata("clear");//清除插件保存的本地数据
});
//插件用的数据都存储在storage.local中
function DBdata(mode,callback,data){//操作本地存储的函数
if(mode=="set"){//保存本地数据
console.log('set-LocalDB');
chrome.storage.local.set({LocalDB: data});
}else if(mode=="get"){//获取
chrome.storage.local.get('LocalDB', function(response) {
typeof callback == 'function' ? callback(response) : null;
});
}else if(mode=="clear"){//清空
chrome.storage.local.clear();
}
}
打开popup.js,把原来的点击事件删掉,在其中加入初始化和连接service_worker的脚本
//popup.js
window.bgCommunicationPort = chrome.runtime.connect();//初始化bgCommunicationPort
$(".checkbtn").click(function(){
bgCommunicationPort.postMessage({//发送到bg,键值可以自由设置
Direct : $(this).attr('id'),//目标
Content : '测试内容',//内容
step : 0//步骤
});
});
$(document).ready(function(){//打开popup时触发,读取之前存储的参数
bgCommunicationPort.postMessage({fromPopup:'getDB'});//向background发送消息
bgCommunicationPort.onMessage.addListener(function(receivedPortMsg) {//监听background
console.log(receivedPortMsg);//这是background发来的内容
if(receivedPortMsg&&receivedPortMsg.Direct){
$(".checkbtn").prop({'checked': false});//初始化按钮
$("#"+receivedPortMsg.Direct).prop({'checked': true});
}
});
});
打开background.js 在其中加入监听popup的脚本
//background.js
chrome.runtime.onConnect.addListener(function(port) {//接收到popup
port.onMessage.addListener(function(receivedMsg) {//监听popup发来的内容receivedMsg
if(receivedMsg.fromPopup&&receivedMsg.fromPopup=='getDB'){//如果接收到了getDB,这里读取数据并返回相当于初始化popup页面
DBdata('get',function(res){
port.postMessage(res.LocalDB);//发送到popup
});
}else{//如果不是,则说明是收到来自popup手动点击设置的数据,存入以用于popup打开时展示
DBdata('set','',receivedMsg)
}
})
});
重载插件,可以看到多了一个service worker,打开可以看到background.js的行为记录
这样再次打开插件,测试按钮就会记录是否勾选了。
因为用户界面(popup.html)相当于日常浏览的网页,关闭之后就销毁了。
所以需要一个地方来存储。这里用按钮的点击事件来触发,把数据通过一直运行在后台的service worker来保存到本地。
在用户界面打开时连接service worker读取之前保存的数据,这样就做到了记录用户界面的数据。
当然,直接在popup.js存取本地数据也是可行的,不过为了演示用户界面和后台的连接所以这样写。而且如果操作本地数据写的到处都是不便于管理也不好看
到现在,这个插件好像也还是什么都做不了
content可以注入浏览的网页,使用得当可以做出很多功能。
在js文件夹中新建content.js。先在manifest.json中加入content的配置:
"content_scripts":[{
"js":["js/jquery.js","js/content.js"],/*content可以随意引入js,因为其内容会在浏览的网页上直接运行*/
"matches":["*://localhost/*"],/*在哪些网页上运行*/
"run_at":"document_end"/* 在页面加载完成时运行 */
}]
然后在content.js中写入
//content.js manifest匹配地址的页面在刷新时会直接执行这里的代码
chrome.runtime.sendMessage(chrome.runtime.id, {//当页面刷新时发送到bg
fromContent: 'getDB'
});
chrome.runtime.onMessage.addListener(function(senderRequest) {//接收到bg
console.log('demo已运行');
var LocalDB=senderRequest.LocalDB;
console.log(LocalDB);
switch(LocalDB.Direct){
case 'TEST':
console.log(123123);
break;
}
});
然后在bg中加入监听content的代码
//background.js
chrome.runtime.onMessage.addListener(function(senderRequest) {//接收到content
sendResponse({msg: '接收到content'});
console.log(senderRequest);
if(senderRequest.fromContent&&senderRequest.fromContent=='getDB'){//接收到fromContent:getDB
DBdata('get',function(res){//从本地取数据
if(res.LocalDB){
var LocalDB=res.LocalDB;
switch(LocalDB.Direct){
//如果是存入的TEST按钮
case 'TEST':
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs){
chrome.tabs.sendMessage(tabs[0].id, {LocalDB: LocalDB});//发送到content
});
break;
}
}
});
}
});
如果不写sendResponse({msg: ‘xxx’});,就会遇到下方的提示
整个运行过程是:
匹配的网页刷新触发content的getDB,发送到bg
bg接收到content发来的getDB的消息,bg获取本地数据,如果是用户界面上勾选的TEST按钮,就发送到content
content接收到bg发来的消息,如果是TEST,则console 123123
和popup一样,content也是可以直接读取本地存储而不用来回连接搞得那么麻烦,这里是展示content和bg的连接代码。
到这里,插件的基本框架已经有了,接下来演示一些实际使用情况
这个网页中含有广告,打开开发人员工具可以看到这个网页中的广告都含有ad这个class,我们可以根据这个标识来识别广告。
在用户界面的网页上增加一个去广告的按钮
DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="css/popup.css" />
head>
<body>
<div class="btn">
测试<input id="TEST" class="checkbtn" type="checkbox" />
div>
<div class="btn">
去广告<input id="removeAD" class="checkbtn" type="checkbox" />
div>
body>
<script src="js/jquery.js">script>
<script src="js/popup.js">script>
html>
在bg中的监听content部分加入removeAD的判断
//background.js
chrome.runtime.onMessage.addListener(function(senderRequest) {//接收到content
sendResponse({msg: '接收到content'});
console.log(senderRequest);
if(senderRequest.fromContent&&senderRequest.fromContent=='getDB'){//接收到fromContent:getDB
DBdata('get',function(res){//从本地取数据
if(res.LocalDB){
var LocalDB=res.LocalDB;
switch(LocalDB.Direct){
//如果是存入的TEST按钮
case 'TEST':
chrome.tabs.query({active: true, currentWindow: true
}, function(tabs){
chrome.tabs.sendMessage(tabs[0].id, {LocalDB: LocalDB});//发送到content
});
break;
//如果是存入的removeAD按钮
case 'removeAD':
chrome.tabs.query({active: true, currentWindow: true
}, function(tabs){
chrome.tabs.sendMessage(tabs[0].id, {LocalDB: LocalDB});//发送到content
});
break;
}
}
});
}
});
在content中监听bg部分加入removeAD的判断
//content.js
chrome.runtime.onMessage.addListener(function(senderRequest) {//接收到bg
sendResponse({msg: '接收到bg'});
console.log('demo已运行');
var LocalDB=senderRequest.LocalDB;
console.log(LocalDB);
switch(LocalDB.Direct){
case 'TEST':
console.log(123123);
break;
case 'removeAD':
//隐藏含有ad的元素,来达到去广告的效果
$(".ad").hide();
break;
}
});
重载插件,勾选去广告。刷新刚才有广告的页面
可以看到广告的div已经被隐藏了
和popup一样,content关闭之后也不会保存数据,当我们在A页面获取数据之后想放到B页面上去,在content上直接跳转是不会把获取到的数据传过去的。所以和bg连接保存本地数据就派上用场了
这里演示如何将github的cookie放到另一个页面展示。
要操作cookie得在manifest配置权限,如下
"host_permissions":["*://*.github.com/*"],
"permissions":["storage","cookies"],/*增加cookie权限*/
"content_scripts":[{
"js":["js/jquery.js","js/content.js"],
"matches":["*://localhost/*","*://*.github.com/*"],/*增加github的匹配*/
"run_at":"document_end"
}]
之后照例在用户界面上增加按钮
<div class="btn">
git<input id="checkGithubtz" class="checkbtn" type="checkbox" />
div>
在bg上增加checkGithubtz的识别,这里稍显不同。
//background.js
case 'checkGithubtz':
//popup设置数据的时候有个step属性,在多步操作的时候就开始发挥作用了
if(LocalDB.step==0){
LocalDB.step = 1;//将step设置成1
chrome.storage.local.set({
LocalDB: LocalDB//保存到本地数据
},function() {
chrome.tabs.update(null, {//将前台页面跳转到设置的url
url: 'https://github.com'
});
});
}else if(LocalDB.step==1){//因为git的地址我们也匹配了所以content在跳转到git之后会还是会回来,不同的是step已经是1了
chrome.cookies.get({//获取cookie
'url': "https://github.com/",
'name': 'tz'
}, function(cookie) {
console.log(cookie.value);//获取到的值
LocalDB.cookie=cookie.value;//把获取到的值放到本地数据的cookie属性里
LocalDB.step = 2;//将step设置成2
chrome.storage.local.set({//获取到cookie之后跳转到第二个页面
LocalDB: LocalDB//保存到本地数据
},function() {
chrome.tabs.update(null, {//将前台页面跳转到设置的url
url: 'http://localhost/test/index.html'
});
});
});
}else if(LocalDB.step==2){//第二步
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){//发送到content
chrome.tabs.sendMessage(tabs[0].id, {LocalDB: LocalDB});
});
}
break;
在content处增加checkGithubtz的识别
//content.js
case 'checkGithubtz':
if(LocalDB.step==2){
$("body").append(''
+LocalDB.cookie+'');
}
break;
这个插件还有很多的不足,实际上它就是几分钟写成的,问题很多,比如用户界面上的开关实际上只能开不能关,还有发送回调的问题。
chrome插件可以有很多功能,比如修改主题、调用下载、操作书签、翻译文字之类的,这里只是展示一些简单的功能。
文档参考https://developer.chrome.com/docs/extensions/mv3/devguide/