在项目开发过程中,时不时会碰上需要使用一些工具来做一些自动操作或者附加功能。特别是有一些外部组件只会提供Web工具,或者如果产品会发布在Web上的时候,在线上的产品中加调试指令显然是不安全的(前段时间刚好有携程线上服务器暴露的调试接口,导致用户信息泄露的事故)。这时候我们就可以借助Chrome来制作一些特别的小工具。 使用Chrome来自作工具有几个好处:其一是对熟悉Web开发的人而言,它用得全是Javascript(当然你也可以用Go语言)和HTML,没有太多额外的学习成本,而且现在的Chrome对HTML5标准支持得也比较好,基本的功能都可以实现;其二是不需要花多少时间在UI方面(作为一个后台开发表示The easier the better);其三是在需要的时候,还能开发为App,直接运行(另外还有一个项目叫Nodejs-webkit,提供了打包成不依赖Chrome本地应用的功能,而且底层用了nodejs,提供了更加强大的系统资源访问的功能)。总而言之,作为开发工具而言已经绰绰有余了。

我是在写第二个Chrome插件的时候写下这篇类似记录的东西,一是有些资源找起来方便,二是下次开发插件的时候不需要从头回顾。第一次写插件刚好是一个页游,为了帮助在页面上抓错误包和快速检查与各个平台之间的交互参数,这一次则是有一个组件提供的管理工具操作太繁琐,写个工具Hack进去然后实现一键操作的。 好啦话不多说,直接上Chrome插件开发流程,Chrome的app开发大同小异,这里就不再另外给出。

概述

资源

不幸地是这两个文档在中国被无情地和谐啦,所以不方便翻墙的话,还可以参考一下某数字公司copy了一份作为它的浏览器的插件开发文档的页面,不过它很久没更新了,缺失比较严重。

执行环境

chrome插件的执行环境主要有三种,一种是后台页,一种是popup页面,还有一种叫内容脚本( content script )。 这三种执行环境分别在三个不同的沙箱中执行。但是可以通过chrome提供的消息管道的形式相互访问。

后台页

后台页当然是运行在后台,也分两种,一种是按需加载的“事件页面”(生命周期的形式有点像手机应用开发),另一种是只要chrome进程存在就会一直保持在线的后台页。 后台页可以用来控制整个插件的功能和处理一些非UI方面的功能。

popup页面

popup页面是存在于浏览器右上角的插件页面(很多插件,比如adblock在右上角都会有一个图标)。 这个页面在点击图标的时候加载,并弹出页面,在页面隐藏的时候被关闭。要注意的是每次点击的时候都会重新加载 popup页面里的某些html属性的权限被安全限制所拦截,但是基本上都可以通过脚本解决。

内容脚本

前面所提到的两种执行环境并不能直接操作网页内容,而这个内容脚本其实就是一个解决这个问题的特殊的脚本环境。 内容脚本必须指定所支持的网页地址,并且在所有匹配的地址中载入这些脚本。并且这些脚本可以直接访问页面里的dom。 不过值得注意的是这个content script并不能直接操纵网页里的脚本的变量,因为它们执行在不同的沙箱中。 并且除非通过addListener的方式注册事件,html里的类似onclick的属性也不会直接访问content script中的函数。

软件结构

入口

chrome插件只有一个必须文件:清单文件mainfest.json。看后缀就知道是JSON格式的,具体内容可以参照文档里的“清单文件格式”部分。值得一提的是,无论是清单文件格式还是popup页面还是载入脚本的api,路径都是相对于插件根目录的。 唯一有一点不一样的是,在content script中如果要获取插件中的资源文件,需要通过_chrome.extension.getURL_接口来获得完整路径。 而其他的诸如权限控制、不同执行环境的配置、资源引用控制都在mainfest.json里完成。

URL权限匹配表达式

插件可以访问哪些页面是要通过匹配表达式指定的,这个表达式有点像通配符,但是又不是通配符。 它的匹配表达式分为 协议、主机和路径三部分。

  • 协议部分可以指定某一个(http、https、file等)或*,但是不能类似http*这样
  • 主机部分每一个第一个.之前可以用*表示匹配全部,也可以指定某个域名
  • 路径部分可以就是字符和*组成的通配符

关于权限和API

插件的几个执行环境都是按mainfest.json的顺序载入的,另外使用方式和一般的网页开发无异。 但是还是有一点点区别。首先,不同环境的拥有的API略有不同,content script中没有大多数全局控制的API;其次,API和开启的权限有关,比如如果开启了tabs权限,popup的执行环境里就会有_chrome.tabs_包;另外,chrome拓展了一些内部接口,比如原生支持JSON类和webkit的一些API。

关于存储

chrome提供了HTML5本地存储,也提供了sync存储。前者可以用来保存离线数据,后者可以用来保存可以被Google帐号同步的应用配置。这是还比较有意思的云存储。

关于通信

由于不同的执行环境(后台、popup、centent script和网页原生的脚本环境)在不同的沙箱中,他们之间要进行通信可以使用chrome的消息管道API。 chrome提供了类似TCP的用于长链接connect API类似UDP的用于短连接的sendMessage API,具体使用方式请参照文档。 另外有一点特殊的地方在于,网页原生的脚本环境一般不受控制,想要和原生的脚本环境交互一般通过脚本注入的方式。所幸chrome的function对象都有totring( )方法。然后通过向页面添加一个script节点的方式可以很容易地实现脚本注入( 当然调试起来麻烦一点点,这也是那个火车票订票插件和视屏网站广告屏蔽插件干的事呦)。

调试

chrome的调试已经非常强大了,在扩展页面上打开开发者模式,可以载入正在开发中的插件的文件夹。 后台页的调试可以在扩张页面点击插件下面的地址打开调试面板。 popup页可以在插件上右键点击“审查弹出内容”打开调试面板。 content script可以在网页上打开网页的脚本调试面板,然后脚本列表那里有个tab是Content scripts

打包和自动更新

chrome浏览器自带了打包工具,在扩展页面上就有。 第一次打包会生成一个密钥文件然后分配一个插件ID,以后每次打包使用这个密钥文件插件ID就不会再变。 如果使用自己的自动更新服务器,自动更新的xml里要填写这个插件ID的,具体的还是看文档吧。比较简单。

_PS:好多干货啊,但是文档是可以选版本的,就没贴很多文档引用链接

再PS:这是我第一次用latex写blog,这玩意虽然功能强大,但是真不怎么方便啊,考虑考虑下次还是markdown算了_