Chrome插件(Extensions)开发攻略

本文将从我的经验出发,讲述为何须要Chrome插件,如何开发,如何调试,到哪里找资料,会遇到怎样的问题以及如何解决等,同时给出一个我的认为的比较典型的例子——获取网页内容,和服务器交互,再把信息反馈给用户。OK,准备开始吧,我尽可能把文章写得好看点,以避免读者打瞌睡。javascript

目录

  1. 为何须要
  2. 为何是Chrome
  3. 须要准备什么
  4. 如何开始
  5. Page Action
  6. Chrome插件结构
  7. 学习资料
  8. 个人例子
  9. 调试
  10. 总结

为何须要

简单地说,浏览器插件,能够大大的扩展你的浏览器的功能。包括但不只限于这些功能:捕捉特定网页的内容,捕捉HTTP报文,捕捉用户浏览动做,改变浏览器地址栏/起始页/书签/Tab等界面元素的行为,与别的站点通讯,修改网页内容……给你增长许多想象空间,试想一想看,你能够用它来识别一些网站上的广告代码,并直接把这些代码删掉,这样你就不会受到广告的困扰了,没错,如你所愿,这样的插件别人已经开发好了,你能够直接用。不过,也要说浏览器插件的弊端,那就是:会带来一些安全隐患,也可能让你的浏览器变得缓慢甚至不稳定。php

为何是Chrome

由于Chrome的插件开发起来最简单,整体上看没什么新的技术,开发语言就是javascript,web前端工程师能很快上手;而Firefox的插件开发则复杂许多,涉及到环境的搭建和一些WEB之外的技术;IE的插件开发就更复杂了,须要熟悉C++和COM技术,固然还要装微软的Visual Studio。html

这里有篇老外写的文章,对比Chrome、Opera和Firefox的插件开发的:http://blog.nparashuram.com/2011/10/writing-browser-extensions-comparing.html前端

应该说Chrome和Opera的插件的开发都不难,但Firefox的则比较棘手,也许你要问,那为何Firefox的插件是最丰富的?我想这有些历史缘由,Chrome出来毕竟比较晚,另外几种浏览器提供的插件的功能也是不尽相同的,OK,咱们仍是言归正传吧。java

须要准备什么

几乎是零需求。Chrome浏览器和一个文本编辑器便可,文本编辑器最好是带语法高亮的那种。谷歌对咱们作技术的人来讲真是太大度了。jquery

如何开始

强烈建议看看官方的说明:https://developer.chrome.com/extensions/getstarted.html程序员

文章不长,照着文章去作,完成后,你就成功开发了第一个Chrome插件,这个插件会弹出一个小窗口,上面显示些阿猫阿狗的小图片。如图:web

这个插件一共有4个文件:ajax

  • manifest.json - 全部插件都要有这个文件,这是插件的配置文件,可看做插件的“入口”。
  • icon.png - 小图标,推荐使用19*19的半透明png图片,更好的作法是同时提供一张38*38的半透明的png图片做为大图标,在我后面提供的例子中,我就是那么干的。
  • popup.html - 就是你所看到的那个阿猫阿狗的弹出页面。
  • popup.js - 阿猫阿狗页面所引用的javascript文件。

这里千万千万注意了,我当初没仔细看popup.html里有一小段注释,这一小段注释说:出于安全考虑,javascript必须与html分开存放。而我想嘛,一个小测试程序,不必分开吧,直接写一块儿不就好了吗?结果javascript死活执行不了,我翻来覆去找不到缘由,还觉得弹出的小窗口不支持javascript,在网上搜索了半天又没有结果,最后才发现是这个缘由,浪费了许多时间,这个事情也必定程度上说明了:细节决定成败。正则表达式

manifest.json中的内容也很是显而易见,我选择其中几个属性讲一下:

{
  "manifest_version": 2,

  "name": "One-click Kittens",
  "description": "This extension demonstrates a browser action with kittens.",
  "version": "1.0",

  "permissions": [
    "https://secure.flickr.com/"
  ],
  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  }
}

"manifest_version":如今应该老是2。

"permissions":很重要的东西,即容许插件作哪些事情,访问哪些站点,假如一个插件的"permissions"里写有“http://*.hacker.com/”,那么这个插件就被容许访hacker.com上的全部内容,包括可能会把你的一些我的信息提交给hacker.com,危险性不言而喻,查看一个插件能访问那些站点的方法是:在chrome的地址栏里输入“chrome://extensions/”(注意:这个页面咱们以后要频繁用到,请收藏一下),而后点对应插件的旁边的那个“权限”,如:

"default_popup":用来指定点击小图标后弹出的小窗口中默认显示的是哪一个html,这个弹出的小窗口就叫作“popup”。

"browser_action":这是一个浏览器级的动做,也就是说,无论你如今在访问哪一个页面,那个小按钮老是显示出来,而咱们的插件若是仅仅是针对某些页面的话,就不适合用这个"browser_action"了。下面咱们来弄一个只有访问博客园(www.cnblogs.com)才会出现的小按钮。

Page Action

chrome-plugin-page-action-demo.7z

这个插件只有4个文件,其中两个仍是图标,那就只剩下一个必须的manifest.json和一个background.js了。

mainifest.json:

{
     "manifest_version": 2,
     "name": "cnblogs.com viewer",
     "version": "0.0.1",
     "background": { "scripts": ["background.js"] },
     "permissions": ["tabs"],
     "page_action": {
          "default_icon": {
               "19": "cnblogs_19.png",
               "38": "cnblogs_38.png"
          },
          "default_title": "cnblogs.com article information"
     }
}

注意:这里是“page_action”而不是“browser_action”属性了。

“permissions”属性里的“tabs”是必须的,不然下面的js不能获取到tab里的url,而这个url是咱们判断是否要把小图标show出来的依据。background是什么概念?这是一个很重要的东西,能够把它认为是chrome插件的主程序,理解这个很关键,一旦插件被启用(有些插件对全部页面都启用,有些则只对某些页面启用),chrome就给插件开辟了一个独立的javascript运行环境(又称做运行上下文),用来跑你指定的background script,在这个例子中,也就是background.js。

background.js

function getDomainFromUrl(url){
     var host = "null";
     if(typeof url == "undefined" || null == url)
          url = window.location.href;
     var regex = /.*\:\/\/([^\/]*).*/;
     var match = url.match(regex);
     if(typeof match != "undefined" && null != match)
          host = match[1];
     return host;
}

function checkForValidUrl(tabId, changeInfo, tab) {
     if(getDomainFromUrl(tab.url).toLowerCase()=="www.cnblogs.com"){
          chrome.pageAction.show(tabId);
     }
};

chrome.tabs.onUpdated.addListener(checkForValidUrl);

代码中,咱们使用了一个正则表达式去匹配url,获取出其中的domain部分,若是domain部分是“www.cnblogs.com”的话,就把小图标show出来,效果以下:

固然了,你如今点那个小图标的话,是没有任何反应的,我没有像官方提供的那个例子那样提供了popup。OK,如今是时候描述下chrome插件的结构了。

Chrome插件结构

须要声明的是,这个结构图是我本身画的,表明我对Chrome插件的理解,可能并不全面,甚至还不是十分准确,但找来找去找不到现成的,只好本身动手,若有谬误,请不吝指出。

如图,manifest.json做为插件的配置文件,同时能够看做程序的“入口”,由于它指定了显示什么图标,background script有哪些文件,content script又有哪些文件,pop up的页面是什么,等等。

什么是popup,什么是background script,相信你们都清楚了,那什么是content script呢?content script就是咱们要注入到页面中的脚本,插件容许咱们往网页中注入脚本,这是一个多么让人有想象力的功能,其功能之强大无需多解释,总的来讲,就是让咱们全面干预页面的内容!也许你立刻会想到,这可能带来很大的安全隐患,没错,有些恶意插件会窃取你的页面信息,而有些有漏洞的插件则可能让你遭受跨站脚本注入(XSS)的攻击;另外一个可能你会想到的问题是:往页面中注入本身的脚本,难道不会跟页面本来的脚本发生冲突吗?能想到这点说明你真的很厉害,若是咱们的注入脚本和页面本来的脚本处于同一个运行环境中,确实会发生冲突,因此,Chrome是另外开辟了一个独立的运行空间,供咱们的Content Script使用的,Content Script能访问DOM的内容,但却不能访问页面本来的脚本(我是说直接访问不行),反之,页面本来的脚本也不能直接访问Content Script。在图中,浅红色的背景块表明Content Script的运行环境,而浅蓝色的背景块表明页面运行环境,另外插件的运行环境我用浅绿色表示,注意,这是三个不一样的运行环境,调试的时候你会充分体会到它们的不一样。

那么,Content Script会在何时运行呢?默认状况下,是在网页加载完了和页面脚本执行完了,页面转入空闲的状况下(Document Idle),但这个是能够改变的,详情可参考https://developer.chrome.com/extensions/content_scripts.html,查看其中的“run_at”。

因为处于不一样的运行环境中,Content Script和Background Script不能直接互相访问,那它们之间如何通讯?经过Message!这个以后的代码中会有。

学习资料

理解了Chrome插件结构以后,我相信你彻底有能力开发一款本身的插件了,固然了,你得本身去google一些资料,这里我就分享下个人方法。

首先,官方的资料必定得看看,https://developer.chrome.com/extensions/index.html,这个上面的资料得大体浏览一下(不须要所有仔细看),这样你可以明白一些术语,知道如何去寻找你的解决方案。

再则,官方提供的例子,能够看看,https://developer.chrome.com/extensions/samples.html,我发现上面的例子有些已经不能用于新版的Chrome了,但不要紧,你只要找你想要的就好了,也不用一个个尝试,就根据你的须要,挑选几个你感兴趣的看看便可。

遇到问题,怎么办?固然是用google去查找问题,但这里我最最最强烈推荐stackoverflow.com,这简直是解决问题的神器!很少解释了,用过便知。

学习过程基本上就是:看个大概,写点代码,调试调试。就能够了。哦,大前提固然是你得有javascript的基础。(你:呵呵,你在逗我吧!)

个人例子

chrome-plugin-cnblogs-article-information.zip

chrome-plugin-cnblogs-article-info-server.zip (服务器端,PHP代码)

好,轮到个人例子登场了。它的功能是这样的:当你浏览博客园的时候,它会启动并尝试获取你浏览的文章的信息(标题、做者和日期),再经过往另外一个服务器发送请求的方式,记录和获取你第一次访问这篇文章的时间,把这个时间连带文章的信息,显示在popup上。听起来挺无聊的功能,但关键是为了演示嘛,如图:

这个插件一共有9个文件,新出现的文件有两个(其它相信你们都很熟悉了),一个是“content_script.js”,这就是前面提到的Content Script,获取和修改页面的内容就靠它了;另外一个是“jquery-2.0.0.min.js”,大名鼎鼎的jQuery,我很喜欢用的js库,其理念是“write less,do more”,能帮我减小不少代码,这是目前最新的2.0.0版,这个版本跟之前的1.x.x的最大差异就是再也不支持IE六、7和8,我我的是十分赞同这种作法的,微软的旧版浏览器都成了Web技术发展的绊脚石了,并且此次咱们用的是Chrome浏览器,果断选择最新版了。

另外还有一个服务器端,为了让问题简化,此次我用了php代码,一个php文件就是整个处理了,没有太多繁杂的配置,简洁,这是php最大的优点。系统结构如图:

抓取网页的内容得依靠content_script.js,而后经过sendMessage/onMessage和background.js交换数据,background.js将url信息经过ajax(XMLHttpRequest)发送给localhost,获取此页面的第一次访问的时间,最后,用户点小图标,popup.html出现,popup.html会读取(代码在popup.js中)background.js中的articleData的数据,把它显示出来。这就是整个过程。

我抓取网页数据的方式并不能确保全部的博客园的文章都能被正常获取,这跟用户使用的博客模板有关系,但我尝试下来大多数文章仍是能够抓取的,我不去适应全部的模板了,毕竟这只是个演示的demo。

另外还需说明的一点是我使用了jQuery作XMLHttpRequest,post的内容不是传统的html表单形式,而是json数据,因此在服务器端这边,就不能直接用$_REQUEST获取,而是经过读取“php://input”的内容获取。顺便谈谈我的对web api的一个见解:“统一”大于“灵活”,这是个人观点,我肯定个人接口的格式是json,使用utf-8编码,因而就一直用下去,调用者不用考虑用XML仍是html表单仍是别的,开发者也没必要多考虑,让这成为一种统一的约定,在团队协助和之后的开发中会很省事。

调试

程序开发,一定要涉及到调试,记得我刚开始作WEB开发前,问一些作了很久WEB开发的朋友,大家是怎样作javascript调试的,我发觉大多数人居然回答:用alert一点点试吧——不是不行,是太原始,过低效了,对吧?其实Chrome直接支持javascript的调试,拥有了Chrome,就至关于拥有了一个强大的javascript调试器了。

Chrome打开开发者工具的方法是<Ctrl>+<Shift>+<I>(Windows版),大体以下:

咱们此次须要关心的有“Elements”、“Sources”和“Console”这三个标签。Elements是用来作DOM分析的,功能有点相似Firebug,帮助咱们分析页面的内容;而Sources,是咱们用来调试javascript的;Console则是咱们的Log的输出窗口,也是一个调试利器。

调试Content Script

如我提供的这个例子,可在Sources的“Copntent Scripts”下看到“content_script.js”而后设断点,执行到断点处时,Chrome会挺住,你能够观察到上面的值,如图:

太cool了,请问你还要一点点alert吗?

调试Background

因为background和content script并不在同一个运行环境中,所以上面的方法是看不到Background的javascript的。要调试Background,还须要打开插件页,也就是“chrome://extensions”。点对应的插件的“generated background page.html”,就出现了调试窗口,接下来的操做就跟前面的相似了。如图:

至于你看到ID,“aajnhhjiia……”这一长串东西,这是chrome自动安排的一个ID。

调试Popup

虽然Popup和Background是处于同一运行环境中,但在刚才的Background的调试窗口中是看不到Popup的代码的。调试Popup还须要这样:

而后……就跟前面差很少了。

一些问题

也许有时候你会发觉调试器不是很灵,至少我用下来感受如此,好比你可能发现断点设不了,或者断点不起做用,或者看不到你本身的javascript文件。个人方法是在插件页中,把对应的插件的“已启用”这个复选框去掉,再从新勾上,而后再点一下“从新加载(Ctrl+R)”,一般能解决问题。固然了,还有些很古怪的问题,还很差重现,整体的解决思路就是从新载入一下,实在不行的话重启浏览器,或者清除浏览器缓存什么的,再试试看。

在作插件调试的时候我还遇到一个十分郁闷的问题,那就是个人Chrome使用了“Go Agent”,关于Go Agent是用来干吗的,这个嘛,能够去google一下,我相信绝大多数程序员都会喜欢上它……可因为使用了这个东西,极可能会致使插件的XMLHttpRequest工做不正常,并且可能你会思索半天也找不到缘由,好吧,暂时把Go Agent停用掉,甚至可能你须要重启下Chrome——个人经验。

总结

我仍是想说,我以为Google对咱们程序员来讲是个很大度的公司,在Chrome这个产品上面就可见一斑。利用Chrome插件技术,咱们能够作许多有用的东西,经过本文,相信你已经知道如何去开发一款Chrome插件了,固然了,Chrome插件的功能是很强大的,我用到的仅是冰山一小角。要深刻,固然还须要更加充分地利用google和stackoverflow.com了。