Chrome插件初窥与实践
某页面获取信息时,需要验证token判断登陆信息。因为某些原因,在测试过程中,测试人员需要采用手动注入token的方式完成登陆,严重影响工作效率。
为了避免影响原始项目,所以采用chrome插件的方式,制作一个简单的登陆页面模拟实际登陆情况,并向原页面插入token用作登陆信息。
本文记录了chrome插件开发的简单概念与插件开发过程,方便以后深入学习chrome插件的开发。
1、核心概念
(1)manifest.json
每一个chrome插件都必须有一个JSON格式的清单文件放在根目录。下面是一些常见的配置项,其中manifest_version、name、version为三个必填项。
{
// 必须
"manifest_version": 2, // 清单文件的版本,必须为2
"name": "插件名称",
"version": "1.0.0",
// 推荐
"default_locale": "en",
"description": "插件描述",
"icons": {...}, // 图标
// 可选
"background":{
"page": "background.html" // 指定后台页面
"scripts": ["js/background.js"] // 指定后台脚本
"persistent": false // 推荐设置后台脚本为非持久
},
"browser_action": { // 工具栏图标(或page_action)
"default_icon": "icon.png",
"default_title": "图标标题",// 图标悬停时的标题,可选
"default_popup": "popup.html"
},
"content_scripts": // 插入网页的脚本
[
{
"matches": ["http://*/*", "https://*/*"], // 匹配页面url,<all_urls> 表示匹配所有地址
"js": ["content.js"], // 多个JS按顺序注入
"css": ["css/custom.css"],
"run_at": "document_start"// 代码注入的时间,可选值: "document_start", "document_end", "document_idle",最后一个表示页面空闲时,默认document_idle
},
{...}, // 可以配置多个规则
],
"permissions": // 权限申请
[
"contextMenus", // 右键菜单
"tabs", // 标签
"notifications", // 通知
"webRequest", // web请求
"storage", // 插件本地存储
],
"default_locale": "zh_CN", // 默认语言
"devtools_page": "devtools.html"// devtools页面入口,注意只能指向一个HTML文件,不能是JS文件
}
(2)content_script
通过content_script,我们可以向指定页面注入JS或CSS。它与插入的页面共享dom,即脚本中使用的window对象与页面中的window对象一致。
content_script可以使用如下几种chrome APIs
- i18n
- storage
- runtime(connect, getManifest, getURL, id, onConnect, onMessage, sendMessage)
(3)background
background是一个运行与浏览器的后台脚本/页面,与当前浏览页面无关。在配置中,可以通过page引入页面,或通过scripts引入JS文件。
通过设置persistent为false,我们可以让background在需要时被加载,在空闲时被卸载,从而释放系统资源。唯一保持后台脚本持续活动的情况是扩展使用chrome.webRequest API来阻止或修改网络请求。webRequest API与非持久性后台页面不兼容。
(4)popup
popup是点击浏览器工具栏上小图标打开的窗口,焦点离开页面即关闭,可做临时性交互。右键后点击“检查”可开启开发者工具进行调试。
可以通过browser_action与page_action进行设置。browser_action可作用于任何页面,page_aciton可作用与部分页面。如vue tools插件,当检测到页面没有使用vue时,插件图标显示为不可用。
2、项目实践
(1)环境搭建
项目主要使用vue-cli与vue-cli-plugin-chrome-ext进行开发,element-ui作为组件库
1、安装vue-cli
npm install -g @vue/cli
# OR
yarn global add @vue/cli
2、初始化一个项目
vue create demo
3、进入项目目录,安装vue-cli-plugin-chrome-ext插件。依次选择插件名称、描述、版本号、使用js或ts
vue add vue-cli-plugin-chrome-ext
4、清理文件,删除src/main.js, src/components, public/favicon.ico 和 public/index.html,最终目录结构
demo
├── README.md
├── babel.config.js
├── package.json
├── node_modules
│ ├── ...
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── manifest.development.json
│ ├── manifest.production.json
│ ├── options
│ │ ├── App
│ │ │ └── App.vue
│ │ ├── index.html
│ │ └── index.js
│ └── popup
│ ├── App
│ │ └── App.vue
│ ├── index.html
│ └── index.js
├── vue.config.js
└── yarn.lock
(2)运行项目
运行npm run build-watch,在根目录生成dist文件夹,在chrome扩展页面chrome://extensions/,勾选开发者模式,选择“加载已解压的扩展程序”,选择dist文件夹,就可以添加扩展程序。添加好的插件如下图所示:

在地址栏右侧,也可以看到添加的插件:

尝试修改src/popup/App/App.vue文件
<template>
<div class="main_app">
<h1>Hello World!</h1>
</div>
</template>
可以发现dist文件被重新编译,文本自动更新(注:如果修改了manifest.json,需要删除插件并重新安装)

(3)开始开发
安装element-ui
npm i element-ui -S
为了减小文件体积,按照element-ui官网所示,采取按需引用的方式
npm install babel-plugin-component -D
// babel.config.js
module.exports = {
// ...
plugins: [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
为popup页面引入需要使用的组件
// src/popup/index.js
// ...
import {Input,Button,Row} from "element-ui";
Vue.use(Input)
Vue.use(Button)
Vue.use(Row)
// ...
使用组件完成页面的绘制
// src/popup/App/App.vue
<template>
<div class="main">
<el-row>
<el-input v-model="form.mobile" type="number" placeholder="手机号"/>
</el-row>
<el-row>
<el-input v-model="form.vericode" type="text" placeholder="验证码">
<el-button slot="append" @click="sendVerifyCode">{{verifyText}}</el-button>
</el-input>
</el-row>
<el-row>
<el-button @click="login" type="primary">登陆</el-button>
</el-row>
</div>
</template>
<script>
export default {
name:'app',
data() {
return {
form: {
mobile: '',
vericode: '',
},
token:'',
verifyText:'获取验证码',
}
},
methods: {
login() {}, // 登陆方法请按需实现
sendVerifyCode () {}, // 获取验证码方法请按需实现
}
}
</script>
如图所示,此时popup页面绘制完成

现在,我们可以在popup页面输入数据,发起请求并获取token,但是popup页面无法访问原页面,所以我们需要将token传递给content,由它将token存储在原页面。
首先新建src/content/index.js文件,并在manifest.development.json(生产环境在manifest.production.json)中添加content的配置
// src/manifest.deveploment.json
"content_scripts":
[
{
"matches": ["http://*/*", "https://*/*"], // 按需要修改匹配的地址
"js": ["js/content.js"],
"run_at": "document_start"
}
],
修改vue.config.js,添加content打包设置
// vue.config.js
// 将content添加进chromeName即可
const chromeName = ["popup", "options", "content"];
至此,content的配置基本完成,下面需要实现的是popup与content之间的通信
popup页面可以通过tabs.sendMessage向content传递数据。首先在manifest.development.json中添加使用tabs的权限
// src/manifest.deveploment.json
{
// ...
"permissions":
[
"tabs"
],
}
修改popup/App/App.vue,向content传递token
// src/popup/App/App.vue
// ...
login() {
this.token = '这是token'
this.sendMsgToContent()
},
sendMsgToContent() { //向content发送信息,让conent在页面的sessionStroage中保存token
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs.length !== 0) {
chrome.tabs.sendMessage(tabs[0].id, this.token, (response) => {
console.log(response)
});
}
});
}
在content/index.js中,接收token值并保存
// src/content/index.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
sessionStorage.clear()
sessionStorage.setItem('token',request)
sendResponse('收到请求');
});
在页面尝试一下,写入成功

(4)问题记录
popup的错误可以在窗口右键选择‘检查’
content可以直接在页面控制台查看
chrome扩展程序里的错误
runtime不加入权限可以使用,加入权限会报错"Permission 'runtime' is unknown or URL pattern is malformed""Uncheked runtime.lastError.Could not establish connetcion.Receiving end does not exist"。重新安装插件并刷新页面,基本就可以了。
(5)打包使用
运行npm run build,生成dist文件夹,扩展程序页面chrome://extensions/选择“打包扩展程序”,可生成crx文件。安装时,可以将crx文件直接拖入扩展程序页面进行安装。(高版本chrome可能会提示“该扩展程序未列在 Chrome 网上应用店中...”,亲测把crx的后缀改为zip,再安装)
参考链接
- vue-cli3开发Chrome插件实践:juejin.cn/post/1(原文链接失效了,可百度标题)
- 一篇文章教你顺利入门和开发chrome扩展程序juejin.cn/post/684490…
- Chrome插件(扩展)开发全攻略:www.cnblogs.com/liuxianan/p…
- Manifest配置文档:developer.chrome.com/extensions/…
- Chrome APIs:developer.chrome.com/extensions/…