Firefox 扩展开发初试

阅读更多

简述



Firefox的扩展开发主要使用JavaScript。界面的制作用XUL,并且可以配合CSS使用。Mozilla的核心XPCOM——跨平台组件模型,提供了一套组件和类,用于诸如内存管理,线程,基本数据结构等,这些都可以在扩展中使用。


Firefox中有Chrome的概念。Chrome 指的是应用程序窗口的内容区域之外的用户界面元素的集合,这些用户界面元素包括工具条,菜单,进度条和窗口的标题栏等。Chrome 提供者能为特定的窗口类型(如浏览器窗口)提供 chrome。有三种基本的 chrome 提供者:


  • 内容(Content):通常是 XUL 文件。
  • 区域(Locale) :存放本地化信息。
  • 皮肤(Skin):描述 chrome 的外观。通常包含 CSS 和图像文件。


开发环境


有一些Firefox的扩展是专门为开发者提供的,使用它们可以使开发更加方便。为了不影响FF使用环境,我们可以用-P参数启动FF创建一个新的配置文件。然后安装下面的扩展:

  • JavaScript Debugger,做JS的调试

  • Extension Developer,一些开发工具

  • Console²,扩展的错误控制台

  • Chrome List,查看Chrome

  • Firebug,用于查看DOM



为了调试容易,还需要设置下面FF的环境参数,在地址栏中输入about:config,然后进行修改
javascript.options.showInConsole = true //把 JavaScript 的出错信息显示在错误控制台
nglayout.debug.disable_xul_cache = true //禁用 XUL 缓存,使得对窗口和对话框的修改不需要重新加载 XUL 文件
browser.dom.window.dump.enabled = true //允许使用 dump() 语句向标准控制台输出信息
javascript.options.strict = true //在错误控制台中启用严格的 JavaScript 警告信息

在 Windows 上,为了可以在js中使用 dump 调试,在FF启动时还需要增加启动参数 -console。

扩展的目录结构


FF的扩展都是以.xpi的文件形式发布,xpi文件实际上就是一个zip文件更改了后缀名。可以通过这个 Extension Wizard来生成一个目录结构。如下:
exname
| build.sh # 两个sh的脚本在windows下没有什么用处,可以直接删掉
| chrome.manifest # Chrome 注册的清单文件
| config_build.sh
| install.rdf # 扩展安装信息
| readme.txt
|
+---content
| firefoxOverlay.xul # 覆盖的界面
| options.xul # 选项设置的界面
| overlay.js # 覆盖的程序
|
+---defaults
| \---preferences
| exname.js # 选项的默认值
|
+---locale
| \---en-US # 英语文件
| exname.dtd
| exname.properties
| prefwindow.dtd
|
\---skin
overlay.css # 样式文件

其中除了chrome.manifest和install.rdf的文件名是固定的,其他文件的名字都随意的。content目录下一般存放扩展界面和程序文件。defaults/preferences下存放扩展选项的默认值文件,FF会自动读取这个目录下所有js的文件,所以文件名是任意的。locale下是各种语言文件,如果扩展支持多语言,那么每一种语言对应到locale下的一个子目录,子目录的名字是像en-US,zh-CN这样的语言代码。skin目录下存放CSS文件,图标之类的。


把这个exname目录拷贝到FF扩展的目录下,一般是
C:\Documents and Settings\<用户名>\Application Data\Mozilla\Firefox\Profiles\<配置文件对应的子目录>\extensions
。然后把目录名由exname改为install.rdf中指定的扩展的ID,FF启动时会自动识别并加载这个新的扩展。


对扩展做了修改之后,不需要重启FF,只要安装了Extension Developer,在Tools菜单中选择
Extension Developer > Reload all Chrome
就可以了。



下载示例中的扩展 Content Filter。这个扩展的功能是对匹配url的网页,查找所有的find并替换为replace。

install.rdf


这个文件中是扩展的安装信息。
如:

xmlns:em="http://www.mozilla.org/2004/em-rdf#">


[email protected]
Content Filter
1.0
Jedy

http://my.homepage.net/
Content Filter
chrome://contentfilter/content/options.xul





{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
3.0

3.0.*






这个文件里需要设置扩展的id,这也是扩展的目录名。设置了optionsURL的话,就可以在FF的扩展列表中使用选项按钮打开这里设置的选项界面。
{ec8030f7-c20a-464f-9b0e-13a3a9e97384}
是Firefox的id,不用更改的,如果扩展还支持Thundbird等其他的Mozilla程序,那么这里会有另一段targetApplication的信息,这会使用其他程序的id。minVersion和maxVersion设置了扩展适合的程序版本,FF的扩展兼容性检查就是查这里的信息。所以如果有的扩展在FF升级后没有升级,结果不能通过兼容性检查,那么可以自己把xpi文件下载下来后改一下maxVersion之后再安装,有不少情况都是可以直接用的。

chrome.manifest


这个内容如下:
content   contentfilter   content/
overlay chrome://browser/content/browser.xul chrome://contentfilter/content/overlay.xul

content行告诉FF可以在content/目录下找到contentfilter的content文件,设置的目录路径是相对于chrome.manifest所在目录的路径。overlay行设置了对浏览器的覆盖文件。这里还可以设置skin,locale的目录等。


Mozilla通过overlay的方式使扩展可以直接更改浏览器的界面,比如可以在菜单栏上增加一组菜单,可以在状态栏上增加图标等。

overlay


通过overlay,在FF的tools菜单上增加了一个菜单项:





在listbox上按键会触发pressDel函数,这个函数使用对象的removeChild方法移除DOM树中的一个子节点。

扩展功能


对于一个实用的扩展来说,通常只有一个选项对话框是不够的,还需要注册一些事件监听函数,或者菜单项提供一个事务处理的入口。见overlay.js:

var contentFilter = {
init: function() {
var appcontent = document.getElementById("appcontent");
appcontent.addEventListener("DOMContentLoaded", contentFilter.filter, true);
contentFilter.patterns.loadAsRegex();
},

filter: function(aEvent) {
var doc = aEvent.originalTarget;
if (doc.nodeName != "#document") return;
var docElement = doc.documentElement;
var p = contentFilter.patterns.patternList;
for (var i = 0; i < p.url.length; i++) {
if(p.url[i].test(doc.location)) {
docElement.innerHTML = docElement.innerHTML.replace(p.find[i], p.replace[i]);
}
}
},
...
};

window.addEventListener("load", function() { contentFilter.init(); }, false);



最后一行定义了一个window.load的监听器,当打开FF的窗口时触发。init函数的定义了页面加载时的监听器并调用了loadAsRegex方法载入配置。


这里定义的contentFilter变量是处于当前窗口的命名空间下,并不是全局的变量,所以在选项对话框中并不能直接调用。因此在options.xul的save函数中
var win= Components.classes["@mozilla.org/appshell/window-mediator;1"].
getService(Components.interfaces.nsIWindowMediator).getEnumerator("navigator:browser");
while(win.hasMoreElements()) {
var browser = win.getNext();
browser.contentFilter.patterns.loadAsRegex();
}

使用了getEnumerator得到所有的浏览器窗口,然后让每一个窗口中的contentFilter对象重新加载配置。

配置


扩展的默认配置参数可以在defaults/preferences目录下定义,如prefs.js:

pref("extensions.contentfilter.url", "baidu");
pref("extensions.contentfilter.find", "hao123");
pref("extensions.contentfilter.replace", "kaixin");

可以在about:config中查找扩展的配置参数。一般命名的方法是extensions.<扩展名>.<参数名>,当没有定义用户的值时,FF会读取这些默认的值。


在程序中可以使用
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService);

得到配置树,然后在找到某个分支
var branch = prefs.getBranch("extensions.contentfilter.");

配置中有4个值的类型:布尔值,整值,字符串和复杂类型。取一个字符串值可以使用getCharPref,如:
branch.getCharPref("name");


这里就是取得extensions.contentfilter.name的值,要注意的是getBranch不会做解析,所以
prefs.getBranch("extensions.contentfilter.na").getCharPref("me")

也是取extensions.contentfilter.name的值,因此,一般在使用getBranch时,branch都是以.结尾的。

发布


讲整个扩展目录下的文件压缩为zip格式,install.rdf为第一层,不要包含扩展本身的目录,然后改后缀为xpi。将这个文件拖到FF中,就会弹出对话框询问是否要安装了。

总结


开发一个功能简单的扩展是很容易的。不过感觉官方的文档不够详细,或者组织的不是很好,想实现个功能很难找到应该怎么做,使用什么API,很多细节的地方不知道该怎么处理。可能要把所有文档浏览一遍才能比较顺手吧。新手可以多看看 Code Snippets或其他人的扩展。

参考链接



  • http://www.ibm.com/developerworks/cn/web/wa-lo-firefox-ext/
  • http://www.rietta.com/firefox/Tutorial/overview.html
  • https://developer.mozilla.org/en/Extensions
  • https://developer.mozilla.org/en/Creating_XPCOM_Components
  • https://developer.mozilla.org/en/XPCOM_API_Reference

你可能感兴趣的:(Firefox,Chrome,JavaScript,CSS,浏览器)