什么是浏览器插件(扩展)?
Chrome插件是一个用Web技术开发、用来增强浏览器功能的软件,它其实就是一个由HTML、CSS、JS、图片等资源组成的一个.crx后缀的压缩包.
为什么学习浏览器插件开发?
增强浏览器功能,“定制”自己专属浏览器
丰富的api
- 书签控制;
- 下载控制;
- 窗口控制;
- 标签控制;
- 网络请求控制,各类事件监听;
- 自定义原生菜单;
- 完善的通信机制;
- 等等
Chrome extension vs Firefox extension?
Firefox插件只能在firefox浏览器中使用。
Chrome除了Chrome、Edge浏览器之外,还可以运行在所有webkit内核的国产浏览器,比如360极速浏览器、360安全浏览器、搜狗浏览器、QQ浏览器等等,Firefox浏览器也对Chrome插件的运行提供了一定的支持。
怎么进行开发调试?
chrome://extensions
edge://extensions/ + 开发者模式
manifest.json + 普通的web开发工具即可
5个核心概念
manifest.json
详细配置项参见:https://developer.chrome.com/docs/extensions/mv2/manifest/1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96{
// 清单文件的版本
"manifest_version": 2,
// 插件的名称(取package.json中的名称)
"name": "__MSG_extName__",
// 插件的版本
"version": "1.0.0",
// 插件描述
"description": "鼠标取词,简化查询流程,即时获取贯众安全威胁情报,提升分析效率。",
// 网站主页,不要浪费了这个免费广告位
"homepage_url": "https://tip.komect.com:9099/",
// 图标
"icons":
{
"16": "img/icon.png",
"48": "img/icon.png",
"128": "img/icon.png"
},
// 会一直常驻的后台JS或后台页面
"background":
{
// 2种指定方式,如果指定JS,那么会自动生成一个背景页
"page": "background.html"
//"scripts": ["js/background.js"]
},
// 浏览器右上角图标设置,browser_action、page_action、app必须三选一
"browser_action":
{
"default_icon": "img/icon.png",
// 图标悬停时的标题,可选
"default_title": "这是一个示例Chrome插件",
"default_popup": "popup.html"
},
// 当某些特定页面打开才显示的图标
/*"page_action":
{
"default_icon": "img/icon.png",
"default_title": "我是pageAction",
"default_popup": "popup.html"
},*/
// 需要直接注入页面的JS
"content_scripts":
[
{
//"matches": ["http://*/*", "https://*/*"],
// "<all_urls>" 表示匹配所有地址
"matches": ["<all_urls>"],
// 多个JS按顺序注入
"js": ["js/jquery-1.8.3.js", "js/content-script.js"],
// JS的注入可以随便一点,但是CSS的注意就要千万小心了,因为一不小心就可能影响全局样式
"css": ["css/custom.css"],
// 代码注入的时间,可选值: "document_start", "document_end", or "document_idle",最后一个表示页面空闲时,默认document_idle
"run_at": "document_start"
},
// 这里仅仅是为了演示content-script可以配置多个规则
{
"matches": ["*://*/*.png", "*://*/*.jpg", "*://*/*.gif", "*://*/*.bmp"],
"js": ["js/show-image-content-size.js"]
}
],
// 权限申请
"permissions":
[
"contextMenus", // 右键菜单
"tabs", // 标签
"notifications", // 通知
"webRequest", // web请求
"webRequestBlocking",
"storage", // 插件本地存储
"http://*/*", // 可以通过executeScript或者insertCSS访问的网站
"https://*/*" // 可以通过executeScript或者insertCSS访问的网站
],
// 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的
"web_accessible_resources": ["js/inject.js”],
// 覆盖浏览器默认页面
"chrome_url_overrides":
{
// 覆盖浏览器默认的新标签页
"newtab": "newtab.html"
},
// Chrome40以前的插件配置页写法
"options_page": "options.html",
// Chrome40以后的插件配置页写法,如果2个都写,新版Chrome只认后面这一个
"options_ui":
{
"page": "options.html",
// 添加一些默认的样式,推荐使用
"chrome_style": true
},
// 向地址栏注册一个关键字以提供搜索建议,只能设置一个关键字
"omnibox": { "keyword" : "go" },
// 默认语言
"default_locale": "zh_CN",
// devtools页面入口,注意只能指向一个HTML文件,不能是JS文件
"devtools_page": "devtools.html"
}content-scripts
Chrome插件中向页面注入脚本的一种形式(虽然名为script,其实还可以包括css的),借助content-scripts我们可以实现通过配置的方式轻松向指定页面注入JS和CSS(如果需要动态注入,可以参考下文),最常见的比如:广告屏蔽、页面CSS定制
run_at为document_start(默认为document_idle)1
2
3
4document.addEventListener('DOMContentLoaded', async function() {
initDialog()
initSearchIcon()
})background scripts(后台脚本)
默认会创建一个background.html,可以理解为常驻的后台页面。
扩展程序是基于事件的程序,用于修改或增强 Chrome 浏览体验。 事件是浏览器触发器,例如导航到新页面、移除书签或关闭选项卡。 扩展在它们的后台脚本中监视这些事件,然后对指定的指令做出反应。
后台脚本可以通过配置(persistent: true/false)表示是否一直活跃。保持后台脚本持续活跃的唯一情况是扩展程序使用 chrome.webRequest API 来阻止或修改网络请求。popup (弹窗)
browser_action或者page_action中配置
生命周期短,打开时重新渲染,失去焦点立即关闭。可以直接通过chrome.extension.getBackgroundPage()获取background的window对象homepage_url (插件主页,天然广告位)
Chrome插件的8种展示形式
browserAction(浏览器右上角)
popup.html+tooltip(title)+badge(icon)pageAction(浏览器右上角)
和browserAction区别在于,不可用是灰色,能根据不同页面个性化启用。(访问百度的时候可用,其他置灰不可用)
3、右键菜单
主要是通过chrome.contextMenusAPI实现
1 | // manifest.json |

4、override(覆盖特定页面)
扩展可以替代如下页面:
- 历史记录:从工具菜单上点击历史记录时访问的页面,或者从地址栏直接输入 chrome://history
- 新标签页:当创建新标签的时候访问的页面,或者从地址栏直接输入 chrome://newtab
- 书签:浏览器的书签,或者直接输入 chrome://bookmarks
1
2
3
4
5
6"chrome_url_overrides":
{
"newtab": "newtab.html",
"history": "history.html",
"bookmarks": "bookmarks.html"
}
5、devtools
每打开一个开发者工具窗口,都会创建devtools页面的实例,F12窗口关闭,页面也随着关闭,所以devtools页面的生命周期和devtools窗口是一致的。devtools页面可以访问一组特有的DevTools API以及有限的扩展API,这组特有的DevTools API只有devtools页面才可以访问,background都无权访问,这些API包括:
- chrome.devtools.panels:面板相关;
- chrome.devtools.inspectedWindow:获取被审查窗口的有关信息;
- chrome.devtools.network:获取有关网络请求的信息;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30// manifest.json
{
// 只能指向一个HTML文件,不能是JS文件
"devtools_page": "devtools.html"
}
//devtools.html
<!DOCTYPE html>
<html>
<head></head>
<body>
<script type="text/javascript" src="js/devtools.js"></script>
</body>
</html>
//devtools.js
// 创建自定义面板,同一个插件可以创建多个自定义面板
// 几个参数依次为:panel标题、图标(其实设置了也没地方显示)、要加载的页面、加载成功后的回调
chrome.devtools.panels.create('MyPanel', 'img/icon.png', 'mypanel.html', function(panel)
{
console.log('自定义面板创建成功!'); // 注意这个log一般看不到
});
// 创建自定义侧边栏
chrome.devtools.panels.elements.createSidebarPane("Images", function(sidebar)
{
// sidebar.setPage('../sidebar.html'); // 指定加载某个页面
sidebar.setExpression('document.querySelectorAll("img")', 'All Images'); // 通过表达式来指定
//sidebar.setObject({aaa: 111, bbb: 'Hello World!'}); // 直接设置显示某个对象
});
6、option(选项页)
插件的设置页面
1 | { |
7、omnibox
注册某个关键字+tab,以触发插件自己的搜索建议界面,然后可以任意发挥了。
监听onInputChanged/onInputEntered等 —> 微博(新浪、腾讯、搜狐)—>获取activetab —> 手动改url
8、桌面通知
Chrome提供了一个chrome.notificationsAPI以便插件推送桌面通知。
1 | chrome.notifications.create(null, { |
消息通信
Content-script植入页面,直接发送请求涉及跨域。所以需要通过于其他部分通信

通常通过backgroundjs进行通信
popup可以直接调用background中的JS方法,也可以直接访问background的DOM
短连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25// 发送请求
// content-script 发送请求
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
console.log(response.farewell);
});
// 插件向content-script发送请求
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
console.log(response.farewell);
});
});
//接受请求
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting === "hello")
sendResponse({farewell: "goodbye"});
// return true;(异步,否则同步)
}
);
如果有多个页面监听消息(onMessage),谁最先执行sendResponse谁就赢,其余监听的回调会被忽略
长连接(类似WebSocket会一直建立连接,双方可以随时互发消息。)
1 | // 发起长连接runtime.connect 或者 tabs.connect或者runtime.connectNative |
port被设计为浏览器扩展的不同部分之间的双向通信方法。发起一个长连接(runtime.connect 或者 tabs.connect或者runtime.connectNative)时,就会生成一个port
插件之间通信
chrome.runtime.onMessageExternal,需要知道插件的id
chrome.runtime.onConnectExternal
页面之间通信
和本地应用之间通信
存储
chrome.storage.sync
chrome.storage.local
// 监听变化
chrome.storage.onChanged.addListener(function (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}".
);
}
});
// 获取
chrome.storage.sync.get(‘options’, (data) => {
Object.assign(options, data.options);
optionsForm.debug.checked = Boolean(options.debug);;
});
// 设置
chrome.storage.sync.set({options});
调试
1、background.html
2、popup.html(保持popup不关闭)
3.1、css
3.2 js

常见API总结
比较常用用的一些API系列:
- chrome.tabs
- chrome.runtime
- chrome.webRequest
- chrome.window
- chrome.storage
- chrome.contextMenus
- chrome.devtools
- chrome.extension
打包和发布
生成.crx文件
谷歌账号+谷歌开发者(5$)上传到应用商店。