目录:
如果你对GmailAssist感兴趣,可以在chrome商店中搜索“Gmail助手”,或点击这里直接访问商店来安装试用;
如果你对GmailAssist的源码感兴趣,可以在我的GitHub上查看它的源码。
一个Chrome扩展包括一系列文件,HTML文件、CSS样式文件、JavaScript脚本、图片等,以及一个最有特点的manifest.json。
1. manifest.json是啥
它是每个chrome扩展有且只有一个的清单文件,它指明了该扩展的基本信息,如名称、版本、需要的权限等等,格式是json。
JSON
JSON是一种独立于语言和平台的数据格式,JSON对象就是一种格式化的静态的数据,接下来的chrome扩展中各模块之间交换信息就是用这种格式。传送时就是作为简单的字符串来传,js在收到json数据的时候可以看成对象来解析,其中可以有层次。其实不仅chrome扩展模块之间的数据交流可以用这种格式,跨应用跨平台的数据交流也可以用这种格式,因为它的数据冗余度很小,并且可读性很好,也容易解析(在我前面的介绍中“JSON”和“json”都有,因为这个大小写是无所谓的,指的都是同一个东西)。下面的manifest.json就可以作为一个例子。
而*.json格式的文件,其内容就是一个json对象。manifest.json就是用这样一种格式化的方法来指明了一个chrome扩展的基本信息。
manifest.json
直接举例来说吧,GmailAssist的manifest.json的部分内容如下:
{ "manifest_version": 2, "name": "Gmail邮箱附件处理助手", "version": "1.9", "default_locale": "en", "description": "查询邮箱内全部附件,支持批量下载,支持批量添加至最新的草稿。要开始使用,在登录Gmail后,点击地址栏右端图标,选择“授权”即可。", "icons": { "48": "images/icon48.png", "128": "images/icon128.png" }, "short_name": "GmailAssist", "page_action": { "default_icon": { "19": "images/icon19.png", "38": "images/icon38.png" }, "default_title" : "__MSG_extName__", "default_popup": "popup.html" }, "background": { "scripts": ["background.js"], "persistent": false }, "content_scripts": [ { "js": ["oauth2/oauth2_inject.js"], "matches": [ "http://www.google.com/robots.txt*"], "run_at": "document_start" }, {...} ], ... }
首先,作为我们理解json格式的例子,上面这段被\'{\'和\'}\'括起来的,就是一个json对象。说白了一个json对象就是一个结构体,其中有各个字段,不同字段之间用逗号隔开,最后一个字段后面不需要逗号。每个字段都是“key:value”这样的形式,每个“key”就可以理解为这个结构体的一个属性,一个具体的属性必然有一个具体的值。(不同于C语言的struct,这里你不需要提前声明一个结构体内有哪些属性,也不需要为每个属性指定其类型,如C语言的int、char等,其类型会在js中解析时自动判断。而类似于C语言中struct的声明的“内容模板”,是不需要你操心的,仅就manifest.json而言,chrome已经定义好了一套“模板”,你在写你的manifest时,按chrome要求的规范来就可以)
json对象中可以包含多个并列的字段(属性),每个属性的值可以是这几种类型中的一个:字符串、数字、对象、数组、布尔和null。字符串就是一串字符直接拿双引号("")括起来(比如例子中的name属性的值"Gmail邮箱附件处理助手"),数字就是不带引号(如例子中manifest_version的值2),数组就是用\'[\'、\']\'括起来的一个或多个元素(这个元素就可以是上面说的字符串、数字、对象、数组等中的一个,当然了,一个数组内的元素们必须是同种类型),布尔就是true、false(不加引号)。每种类型都可以在上面的例子中找到对应的实例。
你的扩展程序在发布和安装的时候,chrome商店和chrome都会检查manifest.json,从中获取必要的信息,并且检查你写的是否合法(例如,如果你的popup.html中有内嵌的js脚本,而你的"content_security_policy"字段是空,你在试图让chrome加载你的扩展程序时,它就会提示错误。这些现在不懂没关系,目前还不重要,有个大概的印象就行,到后面自然会明白)。所谓的必要信息,不仅是一些给人看的信息(如扩展的名称、简称、简介等),还有给浏览器看的信息(如content_script、page_action等字段),后者通知了chrome你的程序的入口等程序运行相关的信息。
具体来说有几个常用字段:
有三个属性是必须的:name, version, manifest_version。
1、"name": 你的扩展程序的名称;
字符串,可以包括中文。这里补充说一点,manifest.json需要按UTF-8编码格式来保存,否则在加载到浏览器中时会报错。
2、"version": 指你的扩展程序的版本号;
字符串,注意虽然版本号一般都是一串数,但它应该是用字符串来表示,而不是数字,所以别忘了引号。版本号最多可以是用3个.分隔的4个数,比如"1.0.0.16"。
3、"manifest_version": 指定清单文件格式的版本(数字);
在Chrome18之后(在chrome中打开chrome://help即可查看当前你的chrome版本),应该都是2,所以直接写2即可。
其他常用字段,我这里只介绍GmailAssist中涉及的,完整的介绍可以参考google官方的文档。另外多说一点,容易百度到,360有一份汉化的chrome扩展开发文档,但我记得这份文档并不太完整,而且翻译质量不是太高,读着比较费劲。为了方便,还是去看google官方的文档吧,毕竟技术人员写的文档,没什么难懂的长难句的,很好读,而且翻译总难免有一些不确切的地方,看官方的文档还是比较保险。(再多说一句,可能新手在FQ上还会有障碍,推荐一个傻瓜式的小工具,蓝灯(*),效果非常好自行百度下载吧)
"default_locale": 这个是指定你的扩展的默认显示的语言,涉及国际化内容,后面会介绍;
"description": 你的扩展的描述,它是显示在chrome应用商店中和chrome扩展页面的,如下图。(其中,商店中显示的应该是你在manifest中通过default_locale指定的默认语言,我这里指定的是英文)
(补充:设置浏览器语言可以通过:1.打开chrome的设置页;2.往下拉找到“显示高级设置...”,点它;3.再往下拉找到“语言”-“语言和输入设置”,点它;4.点左下角的添加,选择你要的语言并确定;5.在左侧列表中点你要的语言,在右侧点“以这种语言显示Google Chrome”;6.重启Chrome)
"description"中还有"icons"字段,它指定你的扩展程序的图标,数字表明分辨率(如128表示图片分辨率为128*128像素)。
"short_name":你的扩展的简称,这个可有可无。
"page_action": 与之平级的还有另一个字段"browser_action",你的manifest中最多出现二者之一。直观地来说,这俩属性分别指明你的扩展在特定网页中才能用,还是打开浏览器后一直能用。更直观的就是,你的扩展的图标出现的位置不同,如下图。
图中是地址栏的最右端,显然地址栏里外各有几个图标。地址栏里的对应的就是指定了page_action的扩展(如GmailAssist),地址栏外的对应的就是指定了browser_action了的。开发时,根据你的需要决定用哪个,并在manifest中指定page_action或browser_action即可。因为GmailAssist是针对Gmail的,所以应该让它在用户在浏览Gmail邮箱时可用,其他时候就直接匿了就行,因此咱们选择page_action。(browser_action和page_action是差不多的,具体细节可以看谷歌的文档)
注意到page_action中有几个字段:
"default_icon"指定你的扩展在地址栏中显示的图标,和前面的description中的icons类似,数字指明分辨率。与description中的icons不同之处在于,后者是指定了在chrome的扩展管理页面(chrome://extension)等处显示的图标,而前者是仅仅指地址栏内的图标。Chrome默认选择19像素的图片,对retina屏显示38像素的。这几个图标不是所有的分辨率都需要各自指定一张图片,但为了保证显示效果,最好是把我这里涉及的几种大小都准备一张图片。如果你不指定自己的图标,也是可以的,chrome会显示一个默认图标。如果你需要图标动态变化,可以参考setIcon(https://developer.chrome.com/extensions/browserAction#method-setIcon)或badge(和setIcon在同一个页面中介绍的)。
"default_title" 是当你鼠标悬停在地址栏中的图标上时,显示的说明文字。
"default_popup" 是你点击扩展图标时,在图标下面弹出的小窗口,如下图是GmailAssist的popup页面。
下面将要提到的几个属性,这里只是暂时进行概念的简单介绍,估计新手很难一下子理解,没关系,有个印象就行,后面我会分别具体说明。
"background": 你的扩展如果需要什么在后台持续运行的部分,就可以通过这个字段来指出。不仅是js,你还可以指定一个自己编写的html,像这样:
"background": { "page": "background.html", "scripts": ["background.js"], "persistent": false }
如果仅仅指定js,chrome会自己生成一个html来在后台跑你指定的脚本;当然如果指定了你自己写的html,它也不会显示出来。
"persistent"值默认为true。为true时,你在background字段中指出的js脚本(注意格式是数组,因而可以有多个脚本)将持续运行在后台,而若persistent为false,则这些脚本将只在事件活动时运行,事件不活动时就会释放其占有的内存等资源。
"content_scripts": 这个属性的内容是一个对象数组,数组内每个对象都指明一系列js脚本及其将要注入的页面(支持通配符*),以及注入时机(可以为"document_start"、"document_end" 或 "document_idle",默认为 "document_idle")。
说明一下,这里的脚本是注入到你要操作DOM的页面的,但这个注入,并不同于在页面中直接写一条引入外部脚本语句。直接在页面中引入的多个js之间是共享命名空间的,但content_script与它们之间是独立的,content_script和页面原有js仅共享页面的DOM元素。在GmailAssist开发初期,这个地方给我带来了一些麻烦,后面我会细说。
暂时介绍这么多字段,这些可以说是最常用的,其他的还有一些很常用,如"permission"等,GmailAssist中涉及的,我会在后面慢慢介绍;而GmailAssist中未涉及的,请参考谷歌的文档。
2. 国际化(多语言支持)相关的文件
在支持多语言的扩展中,除了开头提到的HTML、CSS、js等文件,还会有一个文件夹"_locales",其结构如图:
其中有en, zh两个文件夹,表明GmailAssist分别有英文、中文两个版本。两个文件夹下各有一个文件,叫"messages.json"(两个文件夹中的文件都是这个名字),其中格式化地记录着你的插件将要用到的不同语言版本的各个字符串,例如:细心的话,你可能注意到在上面的manifest.json中"page_action"字段下有个"default_title",其值为"__MSG_extName__"。前面说过,这个字段说明了你鼠标放在图标上会浮出的文字。这个部分就是用了国际化(i18n)的处理,针对不同的语言,这个浮出的文字将显示不同的内容。具体到这个例子上,在_locales->zh文件夹下的messages.json中,就有这样一段:
{ "extName":{ "message":"Gmail附件助手" }, ... }
同样的,在_locales->en文件夹下的messages.json中,有这样一段:
{ "extName":{ "message":"Gmail Attachment Manager" }, ... }
注意到"extName"就正对应着"__MSG_extName__",在插件运行时,chrome就会把"__MSG_extName__",根据当前用户浏览器设置的语言,去插件中_locales文件夹下去找当前语言对应的messages.json,并从中找到"extName"对应的字段,把这个字段中的message属性的值取出,替换掉"__MSG_extName__"。
因此,在zh文件夹中的messages.json,在en文件夹中有一个所有字段key值相同但value值不同的副本。当然,也不要求所有的messages.json都有完整的各个字段名,当chrome去当前语言对应的文件中找不到需要的message内容时,它就会去默认语言的文件夹中找。例如,如果有对应zh-CN(简体中文)的一份messages.json,又有一份zh的,还有一份en的;当前用户浏览器的语言设置为zh-CN,插件manifest中声明的默认语言为en;但zh-CN和zh中的json文件里都没有"extName"字段,那么chrome在查找时会遵循zh-CN,zh,en这样的顺序,找到为止。
messages.json中每个key都可以有另一个字段——"description",用于说明这个key的含义,这个字段是针对翻译人员的,如果你打算自己翻译,就可以不写这个字段。另外,chrome还要求,在manifest.json中声明default_locale字段,和在插件中设置_locales文件夹(即采用国际化)是充要的关系,即有一个就得有另一个,没有这个就不能有那个。
国际化相关的内容,这里没有介绍完,还有一部分放在后面讲脚本时再介绍。
3. 其他的文件
还有一些 *.html,*.css,*.js,都是写网页必然会接触的。复杂的高级特性可以暂时不去深入理解,但基本的语法是很容易掌握的,w3cschool的教程足够详尽,如果你是新手,完全可以花点时间先去学习一下这三者内容中基本的东西。
一个扩展的大体文件结构就是这样,下一篇介绍chrome扩展中的脚本是如何运行及通信的。
最后附上两个链接:
http://www.ituring.com.cn/minibook/950,这本书在我刚接触chrome extension的时候提供了非常大的帮助,讲解非常清晰,并且配有许多小例子帮助理解。
https://crxdoc-zh.appspot.com/extensions/getstarted,这是网上的个人翻译的chrome扩展及应用开发文档,我个人认为翻译质量比360那个文档要高,但我仍然建议你参考谷歌官方的英文文档,而只把这个作为辅助。