Chrome v3 已发布,而本文基于 v2 编写,故本文内容不再具有时效性。
前言
相关文章 谷歌官方文档 (需翻墙)
Chrome 插件开发全攻略 (强烈推荐看这一篇!)
你只需要看完上面那篇文章和掌握一些前端开发基础,就足以自行编写一个 Chrome 插件。本文也是基于上面文章加上自己之前写的插件所记。
什么是 Chrome 插件
如果你用过 Chrome 浏览器的话,也许会用到过一些插件,其中比较知名的就是油猴插件,通过这些插件能够帮你例如自动完成一些功能,屏蔽广告,相当于一个浏览器内置的脚本。应该来说这是 Chrome 扩展开发,不过说 Chrome 插件更顺口,后文也会说成 Chrome 插件。
安装 Chrome 插件
首先打开 Chrome,如下图即可进入插件的管理页面
这时候记得把右上角的开发者模式给勾上,如果不勾上的话你无法直接将文件夹拖入 Chrome 进行安装,就只能安装.crx
格式的文件。Chrome 要求插件必须从它的 Chrome 应用商店(需要翻墙)安装,其它任何网站下载的都无法直接安装,所以可以把crx
文件解压,然后通过开发者模式直接加载。
然后将写好的 Chrome 插件文件夹拖入到刚刚打开的插件管理页面即可。
Chrome 插件知识
manifest.json
是manifest.json
切记不要英文单词打错字,一定要有这个文件,且需要放在根目录上,否则就会出现未能成功加载扩展程序的错误。
background.html 和 background.js
可以理解为后台,同时这个页面会一直常驻在浏览器中,而主要 background 权限非常高,几乎可以调用所有的 Chrome 扩展 API(除了 devtools),基本很多操作都是放在 background 执行,返回给 content,而且它可以无限制跨域,也就是可以跨域访问任何网站而无需要求对方设置CORS
。这对我们后面要在 content 中发送跨域请求至关重要!
我习惯的做法是通过”page”:"background.html"
来导入background.js
或其他 js 代码,如下
// manifest.json
"background": {
"page": "background.html",
},
<!-- background.html -->
<!DOCTYPE html>
<html>
<head>
<title>背景页</title>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/background.js"></script>
</body>
</html>
如果是 scripts 方式导入 js 文件则需要反复修改manifest.json
文件。
关于乱码
有时候你在编写代码中出现了中文可能会出现了如下的乱码,
我遇到的原因是就是我原先的background.html
代码写成如下的情况
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/background.js"></script>
没错,就只写了这两个行,就出现乱码(将 UTF-8 的编码变为了 windows1252),而只需要把 background.html 代码修改成正常的 HTML 结构,也就是上上面的那个代码即可解决该乱码情况。
content.js
我们主要的向页面注入脚本就依靠这个文件,相当于给页面添加了一个 js 文件,但是content
和原始页面共享 DOM,但是不共享 JS,如要访问页面 JS(例如某个 JS 变量),只能通过injected js
来实现(后文会提到)。并且content
不能访问绝大部分chrome.xxx.api
,除了下面这 4 种:
- chrome.extension(getURL , inIncognitoContext , lastError , onRequest , sendRequest)
- chrome.i18n
- chrome.runtime(connect , getManifest , getURL , id , onConnect , onMessage , sendMessage)
- chrome.storage
这些 API 绝大部分时候都够用了,非要调用其它 API 的话,你还可以通过通信来实现让 background 来帮你调用。
inject.js
上文也说到了content
是无法访问页面中的 JS,可以操作 DOM,但是 DOM 却不能调用它,也就是无法在 DOM 中通过绑定事件的方式调用content
中的代码(包括直接写onclick
和addEventListener
2 种方式都不行),但是,在页面上添加一个按钮并调用插件的扩展 API是一个很常见的需求,那该怎么办呢?这时候就需要注入 inject.js 这个文件
document.addEventListener('DOMContentLoaded', function () {
injectCustomJs()
})
// 向页面注入JS
function injectCustomJs(jsPath) {
jsPath = jsPath || 'js/inject.js'
var temp = document.createElement('script')
temp.setAttribute('type', 'text/javascript')
// 获得的地址类似:chrome-extension://ihcokhadfjfchaeagdoclpnjdiokfakg/js/inject.js
temp.src = chrome.extension.getURL(jsPath)
temp.onload = function () {
// 放在页面不好看,执行完后移除掉
this.parentNode.removeChild(this)
}
document.head.appendChild(temp)
}
还没有完,因为注入有权限,所以需要在 manifest.json 声明一下这个文件。也就是下面的这行代码
{
// 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的
"web_accessible_resources": ["js/inject.js"],
}
这样你就能调用
关于消息通信
Chrome 插件主要就 4 个部分组成,injected,content,popup,background,但这 4 个部分所对应的权限,应用都有可能各自不一,这时候就需要通过消息通信,将对应的数据发送到对应的文件,主要也就如下四种通信方式:
popup 和 background
popup 可以直接调用 background 中的 JS 方法,也可以直接访问 background 的 DOM:
// background.js
function test() {
alert('我是background!')
}
// popup.js
var bg = chrome.extension.getBackgroundPage()
bg.test() // 访问bg的函数
alert(bg.document.body.innerHTML) // 访问bg的DOM
background
访问popup
如下(前提是popup
已经打开):
var views = chrome.extension.getViews({ type: 'popup' })
if (views.length > 0) {
console.log(views[0].location.href)
}