什么是浏览器插件?
我们一般以chrome扩展为例子。它是一个可以用web技术开发并增强浏览器功能的软件,实质上是由html、css、js组成的一个.crx后缀的压缩包。
一、重要组成部分
Content Script: 插件植入网页运行的js脚本
Background.js: 插件后台运行的js脚本,有一些浏览器提供的api
Manifest.json: 相当于一个插件的入口或者配置等。包含了插件的名称、描述、版本、权限等等。
Background:
可以理解为一个常驻页面,生命周期是随着浏览器的打开而开启,浏览器的关闭即关闭。一般把需要一直运行的、启动就运行的或者全局的代码放在这里面。
Background的权限很高,可以调用所有的chrome扩展api(除devtools),并且可以无限制跨域,也就是可以跨域访问任何网站而无需要求对方这只cors。其实所有通过chrome-extension://id/xx.html 方式打开的网页都可以无限制跨域。
event-pages
由于background生命周期太长,长时间挂载后台可能会影响性能,与background的区别就是多了一个persistent参数,他的生命周其是在被需要的时候加载,空闲时关闭,比如第一次安装、插件更新、接收到content-script的信息时。
popup
popup是点击browser_action或者page_action图标时打开的一个小窗口网页,焦点离开网页就立即关闭,一般用来做一些临时性的交互。在权限上,它和background非常类似,它们之间最大的不同是生命周期的不同,popup中可以直接通过chrome.extension.getBackgroundPage()获取background的window对象。
manifest
是一个JSON格式的manifest文件,命名为manifest.json
{
// 必须的字段
"name": "my extension",
"version": ".....",
"manifest_version": 2,
// 建议提供的字段
"description": "balabala",
"icons": { //图标要求是png格式;
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
}, ,
"default_locale": "en", //如果扩展有_locales目录,这个字段是必须的。如果没有_locales目录,这个字段是必须不存在的。
// 多选一,或者都不提供
"browser_action": {...},
"page_action": {...},
"theme": {...},
"app": {...}, //用户点击app的图标后导航到的地方
// 根据需要提供
"background": {...},
"chrome_url_overrides": {...},
"content_scripts": [
{
"matches": ["www.google.com/*"],
"css": ["mystyles.css"],
"js": ["jquery.js", "myscript.js"]
}
],
"content_security_policy": "policyString",
"file_browser_handlers": [...],
"homepage_url": "http://path/to/homepage", //扩展的主页url
"incognito": "spanning" or "split", //指定当扩展在允许隐身模式下运行时如何响应
"intents": {...} //一个字典,用于描述扩展或app所提供的全部intent handler。字典里的每个键指定了一个action verb
"key": "publicKey", //是浏览器辅助生成的,不需要指定的
"minimum_chrome_version": "versionString", //需要的chrome的最小版本
"nacl_modules": [...],
"offline_enabled": true, //指定本扩展或app是否支持脱机运行
"omnibox": { "keyword": "aString" },
"options_page": "aFile.html",
"permissions": [
match_pattern: "http://*.baidu.com",
"tabs",
"bookmarks",
""unlimitedStorage",
"backaground"
], //表示扩展可以使用的权限
"plugins": [...],
"requirements": {...}, //指定本app或扩展所需的特殊技术功能,目前只支持指定“3D”
"update_url": "http://path/to/updateInfo.xml",
"web_accessible_resources": [...]
}
content_scripts 详细介绍
Content scripts是在Web页面内运行的javascript脚本。通过使用标准的DOM,它们可以获取浏览器所访问页面的详细信息,并可以修改这些信息。一个扩展可以向一个页面注入多个content_script脚本;每个content script脚本可以包括多个javascript脚本和css文件。
apis
matches: string[]--定义哪些页面需要注入脚本。
css: string[]-- 样式文件;在页面的dom树创建显示之前按照定义的顺序依次注入;
js:按定义顺序注入;
run_at: 控制脚本注入时机:》document_start, document_end, document_idle; 如果是start, 文件在所有css加载完毕后但是没有创建dom并且没有运行任何脚本时候注入;
include_blobs
all_frames: boolean -- 控制是在匹配页面的所有frame中运行还是只是在最上层frame
exclude_blobs
页面url匹配 matches 模式中任意一项以及 include_globs 中任一项,并且不匹配任何 exclude_matches 或 exclude_globs 模式。
编程式注入:意思是说在用户规定的时机触发脚本,比如点击事件的时候。如果要将代码注入页面,扩展必须具有cross-origin 权限,还必须可以使用chrome.tabs模块。可以通过在manifest文件的permissions字段里声明来取得这些权限。一旦设置好了权限,就可以通过调用executeScript()来注入javascript脚本。如果要注入css,可以调用insertCSS()。
example
/* in background.html */
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null,{code:"document.body.bgColor='red'"});
});
/* in manifest.json */
"permissions": [
"tabs", "http://*/*"
],
运行环境
是一个隔离的环境,即它不会访问页面js的变量和函数,可以访问页面的dom。
引用扩展里的文件
通过chrome.extension.getURL()来获取扩展里文件的URL。可以像使用其它url一样使用这些URL
二、通信机制
三、Api部分
action(v3):一般在工具栏控制插件的图标;
alarms:使用chrome.alarms API计划代码定期运行或在将来的指定时间运行
bookmarks: 创建、管理、操作书签相关
browserAction(v2): v2版本的图标相关控制,可以配置popup文件
commands: 可以增加键盘快捷键触发插件的动作;
contextMenus:设置浏览器的右键菜单;可以选择类型例如图片、超链接、页面
cookies: 可以从操作cookies
desktopCapture:捕捉屏幕、窗口或页签
documentScan:从附件中扫描图像;
downloads: 操作管理下载;
events: chrome.events命名空间包含API调度事件所使用的常见类型,以便在发生感兴趣的事情时通知您。
extension: 包括支持在扩展及其内容脚本之间或扩展之间交换消息
history: 交互浏览器的历史记录
nitifications: 通知
pageCapture: 存储页签作为Mhtml
sessions: 查询储存页签和窗口
storage: 可以储存,删除、追踪用户数据改变
tabs: 交互浏览器的页签,可以打开、修改、排序
通讯方法:
content与background
chrome.runtime.sendMessage({
type: "open_set_page",
});
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
const { type } = request;
console.log(request);
if (type === "open_set_page") {
chrome.runtime.openOptionsPage();
}
});
background与popup
function fn() {
return ''
}
var bg = chrome.extension.getBackgroundPage();
const text = bg.fn();
content和popup之间:
content中
chrome.runtime.sendMessage({ info: "我是 content.js" }, res => { // 答复alert(res) })
popup中
chrome.runtime.onMessage.addListener((req,sender, sendResponse) => { sendResponse('我收到了你的来信') console.log('接收了来自 content.js的消息', req.info) })