[Extension] Chrome扩展程序开发

Extension-Chrome扩展程序开发

Posted by cl9000 on September 11, 2017

Chrome Extension

缘由

鉴于经常使用Chrome浏览器,一些用着比较顺手的 Chrome扩展 对于提高生活幸福效率有着很大好处。随即翻阅了下关于 Chrome扩展 开发相关的资料。随即整理如下;
Chrome Extensions developer - API文档

简要说明

Chrome扩展 是一个用Web技术开发、用来增强浏览器功能的软件,一个由HTML、CSS、JS、images等资源组成后经编译发包的一个 **.crx 后缀的压缩包。扩展可以定制爬虫、屏蔽广告、网页实时数据、修改http(s)请求头等等。可以根据自己的需求定制满足自己功能的扩展(Extension)。

Chrome://命令

直接在 Chrome 地址栏输入回车

chrome://命令 描述
chrome://about 查看所有chrome:// 列表
chrome://extensions 显示扩展
chrome://settings 设置
chrome://version 显示当前版本
chrome://history 历史记录
chrome://downloads 下载文件
chrome://newtab 创建新标签
chrome://bookmarks 收藏的标签
chrome://apps 应用操作界面
chrome://components 组件信息
chrome://net-internals 网络事件信息
chrome://memory-redirect 内存使用的统计信息
chrome://dns 显示主机名列表、DNS 状态
chrome://devices 连接的设备
chrome://flags 实验项目,加“#项目名称”锚点可以直接定位到项目
chrome://translate-internals 内置翻译功能页面
chrome://quit 退出浏览器
chrome://restart 重启浏览器

扩展结构

配置文件 - manifest.json

扩展必须有 manifest.json 文件,文件基本如下,
官方模板 manifest.json

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
{   
"manifest_version": 2, // 清单文件的版本,固定值 2
"name": "test echarts - 插件的名称",
"version": "1.0",
"description": "插件的描述",
"icons": {
"16": "img/icon.png",
"48": "img/icon.png",
"64": "img/icon.png",
"128": "img/icon.png"
},
"commands": {
"_execute_browser_action": {
"suggested_key": {
"default": "Ctrl+Shift+V"
}
}
},
// 扩展图标设置,browser_action、page_action、app必须三选一
"browser_action": {
"default_popup": "index.html",
"default_icon": "icon00.png",
"default_title": "图标悬停时的title"
},
// 插件的运行环境
"background": { // 2种指定方式,若设置了scripts字段,那么会自动生成一个背景页
"page": "background.html"
//"scripts": ["js/background.js"]
},
// 权限申请
"permissions": [
"contextMenus", // 右键菜单
"tabs", // 标签
"notifications", // 通知
"webRequest", // web请求
"webRequestBlocking",
"storage", // 插件本地存储
"http://*/*", // 可以通过executeScript或者insertCSS访问的网站
"https://*/*" // 可以通过executeScript或者insertCSS访问的网站
],
// 对页面内容进行操作的脚本
"content_scripts": [
{
//"matches": ["http://*/*", "https://*/*"], // 满足条件执行该插件
// "<all_urls>" 表示匹配所有地址
"matches": ["<all_urls>"],
// 多个JS按顺序注入
"js": ["js/jquery-1.8.3.js", "js/content-script.js"],
"css": ["css/custom.css"],
// 代码注入的时间,可选值: "document_start", "document_end", or "document_idle",最后一个表示页面空闲时,默认document_idle
"run_at": "document_start" // 在document加载时执行该脚本
}
],
// 普通页面能够直接访问的插件资源列表,如果不设置是无法直接访问的
"web_accessible_resources": ["js/inject.js"],
// 插件主页,打开扩展程序主页
"homepage_url": "https://www.bing.com",
}
配置字段说明
browser_action
  1. 如果 browser action 设置了default_popup,popup 可以包含任意你想要的HTML内容,并且会自适应大小。popup 会在用户点击图标后出现。若没有设置default_popup,将执行 chrome.browserAction.onClicked 的内容,若没有设置,就什么都不执行了。

  2. browser_action 对应的还有一个 page_action,区别在于:browser_action 对在浏览器中加载的所有网页都生效;page_action 针对特定的网页生效。一个Extension最多可以有一个 browser_actionpage_action

background
  1. background是插件的运行环境。若设置了scripts字段,浏览器的扩展系统会自动根据scripts字段指定的所有js文件自动生成背景页。也可使用 page 字段指定背景页,**二者只能设置一个**

  2. 一般情况下,会将扩展的主要逻辑都放在 background 中比较便于管理。其它页面可以通过消息传递的机制与 background 进行通讯。理论上 content scripts 与 popup 之间也可以传递消息,但不建议这么做。

content-scripts
  1. content-scripts 是Chrome扩展向页面注入脚本的一种形式(可包含css文件),借助content-scripts 可实现通过配置的方式轻松向指定页面注入JS、CSS(如需要动态注入,可以参考下文),最常见的比如:广告屏蔽、页面CSS定制,等等。
1
2
3
4
5
6
7
"content_scripts": [{  //对页面内容进行操作的脚本
"matches": ["http://*/*","https://*/*"], //满足条件执行该插件
//"matches": ["<all_urls>"], // "<all_urls>" 表示匹配所有地址
"js": ["js/jquery-1.9.1.min.js", "js/js.js"],
"css": ["css/custom.css"],
"run_at": "document_start", //在document加载时执行该脚本
}]
桌面通知

Chrome提供了一个 chrome.notifications API以便插件推送桌面通知

1
2
3
4
5
6
chrome.notifications.create(null, {
type: 'basic',
iconUrl: 'img/icon.png',
title: '标题',
message: '桌面通知'
});
消息通信

官网 - 消息通信文档

普通的消息传递

通过runtimeonMessagesendMessage等方法,可以在各个JS之间传递并监听消息。
在popup.js中,我们让它初始化之后发送一个消息:

1
2
3
chrome.runtime.sendMessage({
method: 'showAlert'
}, function(response) {});

然后在background.js中,监听消息的接收,并进行处理:

1
2
3
4
5
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message.method === 'showAlert') {
alert('showAlert');
}
});

chrome.runtime 的常用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 获取当前扩展程序中正在运行的后台网页的 JavaScript window 对象
chrome.runtime.getBackgroundPage(function (backgroundPage) {
// backgroundPage 即 window 对象
});
// 发送消息
chrome.runtime.sendMessage(message, function(response) {
// response 代表消息回复,可以接受到通过 sendResponse 方法发送的消息回复
});
// 监听消息
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
// message 就是你发送的 message
// sender 代表发送者,可以通过 sender.tab 判断消息是否是从内容脚本发出
// sendResponse 可以直接发送回复,如:
sendResponse({
method: 'response',
message: 'send a response'
});
});

需要注意的是,即便你在多个JS中注册了消息监听onMessage.addListener,也只有一个监听者能收到通过runtime.sendMessage发送出去的消息。如果需要不同的监听者分别监听消息,则需要使用chrome.tab API来指定消息接收对象

长、短连接

Chrome插件中有2种通信方式:
短连接(chrome.tabs.sendMessagechrome.runtime.sendMessage

通过chrome.runtime.connect(或者chrome.tabs.connect)可以建立起不同类型JS之间的长链接。
长连接:
popup.js 信息的发送者需要制定独特的信息类型,发送并监听信息:

1
2
3
4
5
6
7
8
9
10
var port = chrome.runtime.connect({type: "connection"});
port.postMessage({
method: "add",
datas: [1, 2, 3]
});
port.onMessage.addListener(function(msg) {
if (msg.method === "answer") {
console.log(msg.data);
}
});

content-script.js 而接受者则要注册监听,并判断消息的类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 监听长连接
chrome.runtime.onConnect.addListener(function(port) {
console.assert(port.type == "connection");
port.onMessage.addListener(function(msg) {
if (msg.method == "add") {
var result = msg.datas.reduce(function(previousValue, currentValue, index, array){
return previousValue + currentValue;
});
port.postMessage({
method: "answer",
data: result
});
}
});
});
chrome.tabs

要使用这个API则需要先在manifest.json中注册:

1
2
3
4
"permissions": [
"tabs",
// ...
]
1
2
3
4
5
6
7
8
9
10
// 获取到当前的Tab
chrome.tabs.getCurrent(function(tab) {
// 通过 tab.id 可以拿到标签页的ID
});

// 通过 queryInfo,以Array的形式筛选出符合条件的tabs
chrome.tabs.query(queryInfo, function(tabs) {})

// 精准的给某个页面的`content_scripts`发送消息
chrome.tabs.sendMessage(tabId, message, function(response) {});

例子 在background.js中,我们获取到当前Tab,并发送消息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
chrome.tabs.getCurrent(function(tab) {
chrome.tabs.sendMessage(tab.id, {
method: 'tab',
message: 'get active tab'
}, function(response) {});
});
// 或者
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
method: 'tab',
message: 'get active tab'
}, function(response) {
});
});

然后在content_scripts中,进行消息监听:

1
2
3
4
5
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message.method === 'tab') {
console.log(message.message);
}
});
chrome.storage

chrome.storage 是一个基于localStorage的本地储存,但chrome对其进行了IO的优化,可以储存对象形式的数据,也不会因为浏览器完全关闭而清空。
使用这个API需要先在manifest.json中注册:

1
2
3
4
"permissions": [
"storage",
// ...
]

chrome.storage 有两种形式,chrome.storage.syncchrome.storage.local

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 数据储存
StorageArea.set(object items, function callback)

// 数据获取
StorageArea.get(string or array of string or object keys, function callback)

// 数据移除
StorageArea.remove(string or array of string keys, function callback)

// 清空全部储存
StorageArea.clear(function callback)

// 监听储存的变化
chrome.storage.onChanged.addListener(function(changes, namespace) {});

例如 在browser_action完成了用户的登录/注册操作,将部分用户信息储存在storage中。每次初始化时,都会检查是否有储存,没有的话则需要用户登录,成功后再添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// browser_action
// js.popup.js

chrome.storage.sync.get('user', function(result) {
// 通过 result.user 获取到储存的 user 对象
result && setPopDOM(result.user);
});

function setPopDOM(user) {
if (user && user.userId) {
// show user UI
} else {
// show login UI
}
};

document.getElementById('login').onclick = function() {
// login user..
// 通过 ajax 请求异步登录,获取到成功的回调后,将返回的 user 对象储存在 storage
chrome.storage.sync.set({user: user}, function(result) {});
}

而在其他环境的JS里,我们可以监听storage的变化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// background
// js/background.js

// 一个全局的 user 对象,用来保存用户信息,以便在异步时发生 userId
var user = null;

chrome.storage.onChanged.addListener(function(changes, namespace) {
for (key in changes) {
if (key === 'user') {
console.log('user storage changed!');
user = changes[key];
}
}
});

注意:

  1. chrome不允许扩展中的HTML页面内直接内嵌js脚本,而要求所有的脚本都作为外部src来引入
  2. json 文件不允许有注释
正式发布

如何成为一名Chrome应用开发者
Google Chrome 应用商店上传扩展程序

参考

了解以上东西就可以自己整理一个 Chrome扩展,若要深入功能丰富的 extension,便需要参考官网文档(Chrome暂时需要梯子)

参考链接:

一些插件网址

极简插件

字数统计插件
此仅为整理个人笔记,以作备忘,不做商用,请知悉,谢谢。



支付宝打赏 微信打赏

赞赏一下 坚持原创技术分享,您的支持将鼓励我继续创作!