Chrome Extension是什么呢?

简而言之,就是Chrome扩展,它是基于Chrome浏览器的,我们可以理解它为一个独立运行在Chrome浏览器下的APP,当然核心编程语言就是JavaScript咯,然后结合HTML以及CSS来开发。重点是,这个“APP”功能强大,可以独自运行,亦可以与打开的网页、Chrome控制面板(DevTools)、第三方插件等等进行通信,且,Google允许ChromeExtension不必受限于跨域限制,结合以上种种优点,固,我们可以使用ChromeExtension,结合自身业务,开发出许多提高工作效率的工具。

部署ChromeExtension也很简单,如下:

好了,现在来听听属于ChromeExtension它的故事。

一、概要及manifest.json

ChromeExtension是Chrome提出来的一个概念,其实正如上文所说,核心编程语言就是JavaScript,然后提供一切通信、存储接口,大致就差不多了。

需要注意的是,ChromeExtension都包含一个Manifest文件——manifest.json,这个文件可以告诉Chrome关于这个扩展的相关信息,它是整个扩展的入口,也是Chrome扩展必不可少的部分。且必须包含name、version和manifest_version属性,其他常用的可选属性还有browser_action、page_action、background、permissions、options_page、content_scripts。

所以我们可以保留一份manifest.json模板,当编写新的扩展时直接填入相应的属性值就OK了。

manifest.json模板及相关属性解释如下:

{
"manifest_version": 2,
//定义chrome扩展的名称
"name": "My Extension",
//定义chrome扩展的版本
"version": "versionString",
"default_locale": "en",
//定义chrome扩展的描述
"description": "A plain text description",
//定义了扩展相关图标文件的位置
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
},
/*
Browser Actions将扩展图标置于Chrome浏览器工具栏中,地址栏的右侧。如果声明了popup页面,当用户点击图标时,在图标的下侧会打开这个页面。同时图标上面还可以附带badge——一个带有显示有限字符空间(只能显示4字节长度信息)的区域——用以显示一些有用的信息,如未读邮件数等。且Badge目前只能够通过JavaScript设定显示的内容,同时Chrome还提供了更改badge背景的方法。如果不定义badge的背景颜色,默认将使用红色。例如,显示了一个背景颜色为蓝色,内容为“Dog”的badge:
chrome.browserAction.setBadgeBackgroundColor({color: '#0000FF'});
chrome.browserAction.setBadgeText({text: 'Dog'});
*/
"browser_action": {
//通过setIcon方法可以动态更改扩展的图标,chrome.browserAction.setIcon(details, callback)
"default_icon": {
"19": "images/icon19.png",
"38": "images/icon38.png"
},
//定义了当用户鼠标悬停于扩展图标上所显示的文字,chrome.browserAction.setTitle({title: 'This is a new title'})
"default_title": "Extension Title",
/*
定义了当用户单击扩展图标时所显示页面的文件位置, 值得注意的是Chrome不允许将JavaScript代码段直接内嵌入HTML文档,所以我们需要通过外部引入的方式引用JS文件。由于其在关闭后,就相当于用户关闭了相应的标签页,这个页面不会继续运行。当用户再次打开这个页面时,所有的DOM和js空间变量都将被重新创建,所以不要在popup页面的js空间变量中保存数据,而是利用localStorage和chrome.storage将数据保存在用户的硬盘上。
*/
"default_popup": "popup.html"
},
/*
Page Actions与Browser Actions非常类似,除了Page Actions没有badge外,其他Browser Actions所有的方法Page Actions都有。另外的区别就是,Page Actions并不像Browser Actions那样一直显示图标,而是可以在特定标签特定情况下显示或隐藏,所以它还具有独有的show和hide方法。
chrome.pageAction.show(integer tabId);
chrome.pageAction.hide(integer tabId);
另,tabId为标签(下面会具体讲解)id,可以通过tabs接口获取。
*/
"page_action": {
"default_icon": {
"19": "images/icon19.png",
"38": "images/icon38.png"
},
"default_title": "Extension Title",
"default_popup": "popup.html"
},
/*
在Manifest中指定background域可以使扩展常驻后台。background可以包含三种属性,分别是scripts、page和persistent。如果指定了scripts属性,则Chrome会在扩展启动时自动创建一个包含所有指定脚本的页面;如果指定了page属性,则Chrome会将指定的HTML文件作为后台页面运行。通常我们只需要使用scripts属性即可,除非在后台页面中需要构建特殊的HTML——但一般情况下后台页面的HTML我们是看不到的。persistent属性定义了常驻后台的方式——当其值为true时,表示扩展将一直在后台运行,无论其是否正在工作;当其值为false时,表示扩展在后台按需运行,这就是Chrome后来提出的Event Page。Event Page可以有效减小扩展对内存的消耗,如非必要,请将persistent设置为false。注意,persistent的默认值为true。
*/
"background": {
"scripts": ["background.js"]
},
/*
可以指定将哪些脚本何时注入到哪些页面中,当用户访问这些页面后,相应脚本即可自动运行,从而对页面DOM进行操作。属性值为数组类型,数组的每个元素可以包含matches、exclude_matches、css、js、run_at、all_frames、include_globs和exclude_globs等属性其中matches属性定义了哪些页面会被注入脚本,exclude_matches则定义了哪些页面不会被注入脚本,css和js对应要注入的样式表和JavaScript,run_at定义了何时进行注入,all_frames定义脚本是否会注入到嵌入式框架中,include_globs和exclude_globs则是全局URL匹配,最终脚本是否会被注入由matches、exclude_matches、include_globs和exclude_globs的值共同决定.     注意:content_scripts中的脚本只是共享页面的DOM(DOM中的自定义属性不会被共享),而并不共享页面内嵌JavaScript的命名空间。也就是说,如果当前页面中的JavaScript有一个全局变量a,content_scripts中注入的脚本也可以有一个全局变量a,两者不会相互干扰。当然你也无法通过content_scripts访问到页面本身内嵌JavaScript的变量和函数。
*/
"content_scripts": [
{
"matches": ["http://www.google.com/*"],
"css": ["mystyles.css"],
"js": ["jquery.js", "myscript.js"]
}
],
/*
有一些扩展允许用户进行个性化设置,这样就需要向用户提供一个选项页面。Chrome通过Manifest文件的options_page属性为开发者提供了这样的接口,可以为扩展指定一个选项页面。当用户在扩展图标上点击右键,选择菜单中的“选项”后,就会打开这个页面
*/
"options_page": "options.html",
/*
浏览器出于安全考虑是不允许跨域, 但这个规则如果同样限制Chrome扩展应用,就会使其能力大打折扣,所以Google允许Chrome扩展应用不必受限于跨域限制。但出于安全考虑,需要在Manifest的permissions属性中声明需要跨域的权限。
*/
"permissions": [
"*://www.google.com/*"
],
// 为notification服务,桌面通知功能
"web_accessible_resources": [
"images/*.png"
]
}
二、存储

对于网站来说,用户的设置通常保存在Cookies中,或者保存在网站服务器的数据库中。对于JavaScript来说,一些数据可以保存在变量中。
但,如果用户重新启动浏览器,这些数据就会消失。那么如何在扩展中保存用户的设置呢?我们可以使用HTML5新增的localStorage接口。
当然,Chrome为扩展应用提供了存储API,以便将扩展中需要保存的数据写入本地磁盘。Chrome提供的存储API可以说是对localStorage的改进,它与localStorage相比有以下区别:
  1.如果储存区域指定为sync,数据可以自动同步;
  2.content_scripts可以直接读取数据,而不必通过background页面;
  3.在隐身模式下仍然可以读出之前存储的数据;
  4.读写速度更快;
  5.用户数据可以以对象的类型保存。
对于第二点需要说明一下。首先localStorage是基于域名的,而content_scripts是注入到用户当前浏览页面中的,如果content_scripts直接读取localStorage,所读取到的数据是用户当前浏览页面所在域中的。所以通常的解决办法是“content_scripts”通过runtime.sendMessage和“background”通信,由“background”读写扩展所在域(通常是chrome-extension://extension-id/)的localStorage,然后再传递给content_scripts。

使用Chrome存储API必须要在Manifest的permissions中声明"storage",之后才有权限调用。Chrome存储API提供了2种储存区域,分别是sync和local。两种储存区域的区别在于,sync储存的区域会根据用户当前在Chrome上登陆的Google账户自动同步数据,当无可用网络连接可用时,sync区域对数据的读写和local区域对数据的读写行为一致。对于每种储存区域,Chrome又提供了5个方法,
分别是get、getBytesInUse、set、remove和clear,如下:

/*
StorageArea为sync或则local
例, chrome.storage.sync.get(...)
*/
chrome.storage.StorageArea.get(keys, function(result){
  console.log(result);
});
chrome.storage.StorageArea.getBytesInUse(keys, function(bytes){
  console.log(bytes);
});
chrome.storage.StorageArea.set(items, function(){
  //do something
});
chrome.storage.StorageArea.remove(keys, function(){
  //do something
});
chrome.storage.StorageArea.clear(function(){
  //do something
});

Chrome同时还为存储API提供了一个onChanged事件,当存储区的数据发生改变时,这个事件会被触发,如下:

/*
callback会接收到两个参数,第一个为changes,第二个是StorageArea。changes是个对象,键为更改的属性名称,值包含两个属性,分别为oldValue和newValue
*/
chrome.storage.onChanged.addListener(function(changes, areaName){
  console.log('Value in '+areaName+' has been changed:');
  console.log(changes);
});
三、通信

Chrome提供了4个有关ChromeExtension页面间相互通信的接口,分别是runtime.sendMessageruntime.onMessageruntime.connectruntime.onConnect。

且,Chrome提供的大部分API是不支持在"content_scripts"中运行的,但runtime.sendMessageruntime.onMessage可以在"content_scripts"中运行,所以扩展的其他页面也可以同content_scripts相互通信。

/*
extensionId(optional)为所发送消息的目标扩展,如果不指定这个值,则默认为发起此消息的扩展本身;
message(required)为要发送的内容,类型随意,内容随意
options(optional)
callback(optional)用于接收返回结果
*/
chrome.runtime.sendMessage(extensionId, message, options, callback)
/*
callback(required)接收到的参数有三个,分别是message、sender和sendResponse。
其中sender对象包含4个属性,分别是tab、id、url和tlsChannelId,tab是发起消息的标签(下节会详讲)
*/
chrome.runtime.onMessage.addListener(callback)

例如,popup.html与backgroud可以如下通信:

//popup.html
chrome.runtime.sendMessage('Hello', function(response){
document.write(response);
}); //background
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
if(message == 'Hello'){
sendResponse('Hello from background.');
}
});

查看popup.html页面会发现有输出“Hello from background.”

四、标签

标签的意思就是在浏览器中打开的一个个页面,如下:

Chrome通过tabs方法提供了管理标签的方法与监听标签行为的事件,大多数方法与事件是无需声明特殊权限的,但有关标签的urltitlefavIconUrl的操作(包括读取),都需要声明tabs权限。

"permissions": [
"tabs"
]

获取标签信息。Chrome提供了三种获取标签信息的方法,分别是getgetCurrentqueryget方法可以获取到指定id的标签,getCurrent则获取运行的脚本本身所在的标签,query可以获取所有符合指定条件的标签。

以getCurrent为例,代码如下:

chrome.tabs.getCurrent(function(tab){
console.log(tab);
});

重点是,ChromeExtension也可以与指定的标签通信(标签中注入了"content_scripts"),方法如下:

chrome.tabs.sendMessage(tabId, message, function(response){
console.log(response);
});
五、拓展阅读

[1]. Chrome Extensions

[2]. Chrome扩展及应用开发

ChromeExtension那些事儿的更多相关文章

  1. 说说Makefile那些事儿

    说说Makefile那些事儿 |扬说|透过现象看本质 工作至今,一直对Makefile半知半解.突然某天幡然醒悟,觉得此举极为不妥,只得洗心革面从头学来,以前许多不明觉厉之处顿时茅塞顿开,想想好记性不 ...

  2. 总结iOS开发中的断点续传那些事儿

    前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...

  3. setTimeout那些事儿

    一.setTimeout那些事儿之单线程 一直以来,大家都在说Javascript是单线程,浏览器无论在什么时候,都且只有一个线程在运行JavaScript程序. 但是,不知道大家有疑问没——就是我们 ...

  4. Javascript中关于cookie的那些事儿

    Javascript-cookie 什么是cookie? 指某些网站为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密).简单点来说就是:浏览器缓存. cookie由什 ...

  5. webpack那些事儿

    webpack那些事儿01-webpack到底是什么 webpack那些事儿02-从零开始 webpack那些事儿03-热插拔 hot webpack那些事儿04-spa项目实战分析 webpack那 ...

  6. 关于JSON的那些事儿

    JSON的那些事儿 曾经有一段时间,XML是互联网上传输结构化数据的事实标准,其突出特点是服务器与服务器间的通信.但是业内不少人认为XML过于繁琐.冗长,后面为了解决这个问题也出现了一些方案,但是由于 ...

  7. MVC之前的那点事儿系列(10):MVC为什么不再需要注册通配符(*.*)了?

    文章内容 很多教程里都提到了,在部署MVC程序的时候要配置通配符映射(或者是*.mvc)到aspnet_ISPAI.dll上,在.NET4.0之前确实应该这么多,但是.NET4.0之后已经不要再费事了 ...

  8. MVC之前的那点事儿系列(8):UrlRouting的理解

    文章内容 根据对Http Runtime和Http Pipeline的分析,我们知道一个ASP.NET应用程序可以有多个HttpModuel,但是只能有一个HttpHandler,并且通过这个Http ...

  9. CSS知识回顾--读《CSS 那些事儿》笔记

    由于之前有了解过CSS的相关知识,有了一定的基础,所以读起<CSS 那些事儿>不是很有难度,况且我现在读起来时,CSS3和HTML5比较流行,这里只是记录一些CSS知识记录,不做详细铺开, ...

随机推荐

  1. 记录下Webapi签名机制

    首先,写这篇文章的原因是因为最近某一个项目中的接口被人为调用了,导致了数据库数据被串改.虽然是内部人无意点的,但还是引起了我的担忧,所有整理了下关于Webapi的相关签名机制. 一.我们在开发接口时, ...

  2. 有关CUBLAS中的矩阵乘法函数

    关于cuBLAS库中矩阵乘法相关的函数及其输入输出进行详细讨论. ▶ 涨姿势: ● cuBLAS中能用于运算矩阵乘法的函数有4个,分别是 cublasSgemm(单精度实数).cublasDgemm( ...

  3. T-SQL 删除重复数据SQL

    WITH cte AS (   SELECT roleid,permissionid,      row_number() OVER(PARTITION BY roleid,permissionid ...

  4. Mysql 删除重复记录,只保留最小的一条

    delete from `jb_postcontent` where id not in(select min(id) from (select * from `jb_postcontent`) as ...

  5. queue的入门

    #include "iostream"#include "queue" using namespace std; void main12(){ queue &l ...

  6. mysql +keeplive+drbd高可用架构

    1MySQL+DRBD+keepalived高可用架构 DRBD(DistributedReplicatedBlockDevice)是一个基于块设备级别在远程服务器直接同步和镜像数据的开源软件,类似于 ...

  7. Python中的输出

    1.Python的输出语句 Python输出语句是print,但是python2.x与3.x又有点区别.python2.x输出 print "xxx"能成功执行,而3.x不行,所以 ...

  8. 532. K-diff Pairs in an Array

    Given an array of integers and an integer k, you need to find the number of unique k-diff pairs in t ...

  9. struts2+spring3+hibernate3+mysql简单登录实现

    1.导入相关的jar包 2.建立数据库 1 create table account( 2 id int(10), 3 user varchar(50), 4 paw varchar(50) 5 ); ...

  10. Gmail,QMail,163邮箱的 IMAP/SMTP/POP3 地址

    我们在客户端设置邮箱或者使用 PHPMailer 发送邮件的时候,我们都会去查找这些邮箱的 IMAP/SMTP/POP3 地址,这里就列出 Gmail, QMail, 163邮箱这三个常用邮箱的这些地 ...