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/…