前言:
最近有个课程项目,由于对插件开发很感兴趣,所以花了较大的功夫去研究chrome extension开发。最近一阵,读文档、别人的总结、示例代码不在少数,怕以后自己忘了,所以还是趁热打铁写下来。由于本人理解能力有限,对于一些现象给出的解释可能不全面或者有偏差,欢迎大家指正!
写博客的经历不是很丰富,在此请允许一个小有心得的菜鸟谈谈chrome插件开发的一些知识,希望能对和我一样菜鸟级别起步的人提供便利!
先来讲讲如何创建属于自己的chrome插件!我假设读者和我一样,会一点点js的语法,能够看得懂jQuery语句。注释中的内容可以无视!
(实在不会,可以看看 http://www.w3school.com.cn/ 一个绝佳的自学的网站,碰到不懂的时候我也会经常查查这个网站)
=========================华丽丽的切割线================================================
进入正题:
首先,我们需要manifest.json文件来声明我要写的插件的相关信息。可以把manifest.json理解成插件的入口,即chrome需要通过manifest.json来理解你的插件要引用哪些文件、需要哪些权限、插件图标等信息。ok,那就先来写manifest.json文件吧:
/*以我新手上阵写的插件为例:cyber_watcher,名字看起来挺87的,其实就是追踪用户(也就是浏览器使用者=>我自己)登陆过的网址,并且根据域名进行计数。说白了,就是统计一下自己的上网习惯。*/
{ "manifest_version": 2, "name": "cyber watcher", "version": "0.0.1", "background": { "scripts": ["jquery.min.js", "background.js"] }, "browser_action": { "default_icon": "ico.png", "default_title": "cyber watcher", "default_popup": "popup/popup.html" }, "permissions" : ["tabs","http://*/*"], "content_scripts":[{ "matches":["http://*/*"], "js":["jquery.min.js", "watcher.js"], "run_at":"document_end" }] }
“manifest_version”现在都是第二个版本了,现在都需要适应新的规范,所以照着写就可以了(第一个版本我也只是在别人的插件代码中看到过,主要是一些manifest变量命名的方法和语法不同);“name”就是你的插件的名称啦~在需要扩展程序显示名称的时候显示出来的文字;“version”是版本号;“background”定义后台的一些特性,比如可以为后台(后台有什么作用?先留个疑问吧!)添加脚本;“browser_action”设置扩展栏的信息,也就是为你的插件在扩展栏里面添加一个图标(ico.png),鼠标悬浮的时候显示插件名称(cyber watcher),鼠标点击的时候显示一个弹出页面(popup.html);其实还有一个“page_action”,设置的是地址栏的信息,其中地址栏的图标可以控制它是否显现。
/*btw:扩展栏?地址栏?如下图所示-摘自chrome开发手册*/
/*蓝色小格子 就是地址栏的图标,黄色小格子 就是扩展栏(目测也叫工具栏)的图标。如果你的插件只是针对于某些特定的网站,建议设置成page_action,只在登陆特定网站的时候才显示插件图标。btw:为你的插件找个19*19px的图标吧~*/
/*顺便吐槽一下:我就读的学校有个大神写了chrome选课插件,只适用于我校的选课系统,不过他居然把图标设置在扩展栏,想到我居然发现该大神设计不合理的地方,还是有点小开心的呢! */
"permission"设置插件的权限,其中"tabs"允许插件访问标签页,后面的网址允许插件向这些网址发送ajax请求(同时还获取了其他权限,不过对于小插件一般用不到),“http://*/*”星号是通配符,表示的就是所有http请求的页面!“content_scripts”就是你向指定的页面注入的js代码,其中页面由match指定,run_at指定的是这段js载入的时机。
注意:写manifest.json非常痛苦的一件事情就是区分 “[” 和 “{”。在js中,“[”用于定义数组,“{”用于定义对象。基于这种理解,我们再看content_scripts属性的构成:由于一个插件可以针对不止一个网页/网站,content_scripts中就应该定义你所有需要导入js的页面的导入信息,因此是一个数组,最外面是一个“[”。而数组中的每一个元素是一个对象,对象中的每个属性对应了content_scripts的一条导入信息。其中,“js”属性对应需要导入哪些js文件,而导入的js文件不止一个,因此又是一个数组。数组的对象之间用逗号分开,对象的属性之间用逗号分开。不知道这样解释之后,看manifest.json会不会更加清晰呢?
manifest.json写好之后,其中引用过的文件一定要被创建(比如popup.html),否则会报错。
========================又来华丽丽的分割线===============================================
配置方法:
一个插件需要的基本东西几乎具备了。那插件如何运行呢?
1.打开chrome右上角扩展栏里面,”三条杠“=>"工具"=>"扩展程序",进入到chrome的插件管理页面(这个页面很重要,调试必要,要,要,切克闹);
2.选择“载入正在开发的程序”,然后选定你插件存放的文件目录(即包含了manifest.json的目录),即可;
/*如果你的插件有代码更改,需要点击 重新加载 才能更新插件哦~*/
/*啊咧咧?“打包扩展程序”有什么用?chrome的插件格式是“.crx”后缀的,打包的话就是生成.crx文件,你如果想要把你的插件给别人用的话,可以把.crx文件发给他,然后他直接把.crx拖入到刚才说的插件管理页面,就成功安装了你的插件了!*/
-------------------------------------------------------------
--------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------
至此,一个插件就配置好了!在写一个实用的插件之前,我们可以先来做点简单的测试项目:
比如我可以在把manifest中的content_scripts写成:
"content_scripts":[{ "matches":["http://www.baidu.com/*"], "js":["test.js"] }]
在test.js中写:
var div = document.createElement("div"); var body = document.getElementsByTagName("body")[0]; div.innerHTML = "Hello,World!"; div.style.position = "fixed";/*固定定位*/ div.style.left = "100px"; div.style.top = "100px"; /*显示在距离窗口左边100px,顶部100px的位置*/ div.style.color = "red"; /*字体颜色红色*/ div.style.fontSize = "50px";/*字体大小50px*/ body.appendChild(div);
/*新手写的代码,没有用jQuery,大神们见笑了*/
然后把manifest写好,按照之前的方法配置一遍,/*记得找个好看的图片作为你的插件图标哦!*/ 如果你已经配置过了,就点击“重新加载”。
登陆 百度,看看是不是在左上角显示了一个大大的“hello,world”呢?
如果你写了popup.html文件,那么你点击右上角自己的插件图标,看看弹出的是不是你写的页面?
/*什么?没有出现预期的效果?两种可能:1.你的代码写错了 2.你一定是在逗我*/
/*代码错了?我怎么知道?
1.打开插件管理页面,看看有没有报错信息,有的话一般都是出现在manifest.json的语法错误上,建议直接copy别人的manifest.json,然后进行修改。
2.打开控制台,看看有没有什么报错信息。chrome的话F12就可以快速启动console了。*/
====================最后的华丽丽的分割线=================================================
参考阅读:
以上内容,含部分言论,可参见我读过的一篇博客:
[1] http://www.cnblogs.com/guogangj/p/3235703.html 谷歌chrome自然而然找到的博客,写得很好,刚开始起步写插件可以下载他的作品参考(我就是这么做的),我的总结,很大部分是对他的总结的再总结(掺杂了一点点我个人的理解方式)
顺便贴下我写的插件代码(王婆卖瓜,见笑了!TAT):
[2] watcher.zip 追踪自己上网的记录的一个小插件,多一份代码,多一份参考吧...
[3] http://developer.chrome.com/extensions/getstarted chrome插件开发手册上给的样例,全英文的,不过挺好懂的,写的也比较简单,不过绝对是参考范本!
chrome插件(二)-区别三个环境
前言:
这句话一定要写在前面:这只是一个刚开始学习写插件的人写的总结,我尽可能严谨,但能力限制不允许啊TAT!所以有什么错误,欢迎指正交流~
注释部分大多为个人理解,未经详细考察推敲,可以直接无视。如有错误,欢迎戳我,及时纠正我的理解误区!thx----q:894355570
进入正题:在extension的编写过程中,会发现:比如我在background.js里面定义了一个函数,然后在popup页面中不能调用!进一步研究,你会发现后台和popup两者之间,并不能共享变量。事实上,这里有三个环境(上下文),为了描述方便,我喜欢称之为background、popup、content。算上浏览页面自身的脚本,一共有四个环境。他们相互独立,拥有不同的上下文,不能共享任何js变量。
/*在同一个上下文中,变量/函数共享同一个命名域/名字空间,所以能够调用同一个文件中其他的变量/函数。比如,我在博客园里有个账号,那么在博客园的域内就能够搜索到我,我也可以通过一定途径,找到同样在博客园的其他人;但你在其他博客网站想查找我的话,无法查到,因为就压根没有我这个用户。*/
===============================华丽丽的分割线===============================================
使用控制台:
在chrome中,按F12后选择console标签,或者ctrl+shift+J都可以快速启动当前页面的控制台。
/*我不知道具体的细节,不过就目前的经验看来,当前页面的console和当前页面载入的脚本属于同一个上下文*/
在console中,你可以访问页面脚本的变量,或者调用页面脚本中的函数。
关于console的更多巧妙用法,可以参考开发手册:
http://developer.chrome.com/devtools/docs/console
以下挑出console中两个非常有用的函数,简直就是在控制台中检测程序的神器:
1.console.log(msg):在控制台中输出信息。如果参数是对象的话,会输出[Object Object]。/*log其实是把参数当成字符串解析了!*/
2.console.dir(obj):在控制台中输出信息。不过能够输出对象,通过展开/折叠可以查看对象的各个属性。如下图!/*dir其实是把参数当成对象解析了!不信,可以试试console.dir("abcd");*/
/*一般情况下,我都是在控制台中测试一些基本函数的用法,或者检测自己函数的正确性!把代码直接copy到控制台,然后回车,然后看返回值。*/
后台background:
后台的脚本文件在manifest的“background”属性中设置,比如设置为“background.js”。
如果你在background里面定义了一个变量,你会发现在ctrl+shift+J跳出来的console里面访问不到该变量!这个时候可以深刻体会到后台和页面脚本处于不同的环境!
不过,通过在后台控制页面==>点击 generated_background_page.html 就会弹出后台的console啦!在弹出来的console里面,可以与background.js里面的变量/函数进行交互。
-------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------
弹出页面popup:
所谓弹出页面,就是你点击插件图标时,弹出来的页面。同样,它既不能直接访问后台,也不能访问页面脚本,也处于一个独立的环境之中。
/*机智的你,一定发现了:所谓不能直接访问,言外之意就是可以间接访问。以后再谈*/
可以直接右键==>审查弹出内容,或者点开弹出页面==>右键==>审查元素 就可以调用popup的专属console啦~
-----------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
插件脚本content:
/*不得不说,content环境好像也只有我自己这么称呼,只是为了方便描述,不是什么规范的称呼。它是插件注入的脚本运行的环境。目测手册上称这个环境为 孤立环境(isolated world)我想表达的意思就是:下文提到的 content环境 = isolated world*/
特别需要知道的是,content和页面脚本也是互相独立的两个环境,即便content给你的感觉像是和页面脚本距离最近的一个!
所谓独立,也就是说你不可能在content_scripts的js文件里面,调用原网页脚本的任何变量/函数。
然而,相当高端的事是:content环境可以访问原页面的DOM结构,也就是说,它和页面脚本一样,能够操作页面的任意一个元素!这就意味着,你可以全面干预最终显示在你眼前的页面!
之前说过了,你在浏览页面调用出来的控制台,和你的浏览的页面脚本属于同一个环境,也就是说:这个控制台不能访问content_scripts的js文件中的任何变量/函数。说白了,就是content环境没有属于自己的控制台。/*至少根据目前的我的理解来说,没有;不过这样,才能体现 isolated world的高贵冷艳嘛~*/
关于Debug:
在控制台中,有很多手段可以辅助你debug,我自己也是菜鸟,我就贴两个我最常用的手段吧!
1. 设置断点,在控制台页面选择“Sources”标签,找到你想检查的脚本,然后直接点击行号即可设置断点;
/*如图,我在watcher.js的第五行设置了断点,但程序运行到这一行时会处于暂停状态,可以通过右上角来继续控制程序的运行。通过右边框中的Call Stack还有Scope variables还可以看到当前环境中的栈情况以及环境变量。*/
2.console.log()+console.dir()这两个函数配套使用,加到源代码中,可以在控制台中输出临时变量,便于检测逻辑的正确性。
除此之外,虽然笨,但别忘了还有alert()函数,相当于内置在你源码中的断点:运行到alert函数时,会显示一个警告框,在警告框被处理之前,脚本暂停运行。
============================华丽丽的分割线呦=======================================================
小结:
说到底,写插件的时候,务必要意识到background、popup、content是三个相互独立的环境,算上原页面的脚本环境,一共就有四个独立环境了。其中,content和页面脚本共享页面的DOM结构,能够对文档元素进行修改!我自己画了个图,便于理清我自己的理解,如有错误,欢迎尽早指正(至少我的理解在我目前的编写过程中屡试不爽):
/*或许你和我一样,很有疑问:为什么要有这么多独立的环境?手册上说:这是为了安全性考虑!毕竟需要意识到:你可以干预别人的网页,反过来,别人也可以通过页面脚本干预你的浏览器,窃取你的浏览数据什么的,都是有可能的!如果不把这些环境隔离开来,我们上网的信息就会暴露在别人面前,想想还是挺可怕的!当然,这只是我个人说服我自己的一种理解,毕竟对网络安全不太懂*/
===================================华丽丽的分割线=============================================
参考阅读:
[1]http://developer.chrome.com/extensions/overview 开发手册上给出的一个整体视图的理解
=================2014/4/8=补=============================
这里补充一个功能,即chrome.tabs.executeScript函数,它也可以向指定页面植入脚本。
可以看看这里:
所不同的是,这个函数只能在background.js里面使用(至少我测试出来是这样,或者我的测试方法有问题),可以传递三个参数,即:
1.目标标签页的id,这个可以通过tabs.query函数来获取特定的标签页;
2.具体插入的脚本,可以直接是代码,{code:“代码”},也可以是文件{file:“code.js”};
3.回调函数。
由于是动态导入的,也就是是说你可以在任何特定情况下导入js代码。
另外,虽然content_scripts是事先准备好的,而executScript是动态导入的,但是,它们属于同一个上下文,也就是说,动态导入的时候,是可以访问到你在content_scripts中定义的变量或者函数的。(这点亲测通过)
=======================================================
和论坛上另外好友交流的时候我又学到了一招,受教于他人才知道的,在这里交流一下:
由于content_scripts和原页面脚本不属于同一个上下文,那问题来了:我偏偏就想调用原页面脚本里面的函数,我就是想访问它的变量或者函数,怎么办?
首先,要基于这样一个前提:我对原页面脚本充分了解,我的目标代码也只针对特定网页
方法:找到原页面脚本所在的<script>标签,然后append要添加的代码
一般来说页面的脚本在<head>标签里面,
1
|
$(
"script"
,
"head"
).append(
"alert('hello,world!')"
);
|
在本地亲测通过,成功调用原页面脚本中定义的函数。由于一般网站构架过于复杂,尚未在知名网站上测试成功过(在百度上测过,跪了,尚不知晓原因)
转自:http://www.cnblogs.com/leenham/p/3597705.html