编写Firefox扩展
FireFox和Thunderbird有很好的扩展架构,你可以通过XML和ECMAScript结合的方式而不用通过编写C程序的方式来编写扩展
在这个Blog里面,我将会看看如何创建一个简单的扩展,这个扩展将一个“Hello World”菜单项添加到FireFox的Tools菜单中。
<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 297.75pt; HEIGHT: 193.5pt" type="#_x0000_t75" alt="Hello World item in the Firefox Tools Menu"><imagedata src="file:///C:%5CDOCUME~1%5C%E9%99%88%E9%94%90%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.gif" o:href="mhtml:file://E:\FireFox\Duffblog%20Writing%20an%20Extension%20for%20Firefox.mht!http://www.dubh.org/jdevimages/ff_hello_toolsmenu.png"></imagedata></shape>
Creating contents.rdf
contents.rdf是一个资源描述框架Resource Description Framework (RDF)文件,这个文件描述了扩展的内容,RDF采用了XML语法,它提供了一个可以让应用程序非常容易处理的数据模型。如果你编写简单的扩展,你不需要对E\RDF有很多的了解,但是如果感兴趣的话,你需要从W3C获得更多信息。
首先,创建一个名称为content的目录,这个目录将包含扩展主要的内容(Content)。contents.rdf要放在这个目录下面。你需要创建一个如下所示的目录结构:
c:\myextensions\
+- helloworld
+- content
+- contents.rdf
下面是 contents.rdf.的代码
<?xml version="1.0"?>
<RDF:RDF xmlns:RDF="http://www.w3.org/<chsdate year="1999" month="2" day="22" islunardate="False" isrocdate="False" w:st="on">1999/02/22</chsdate>-rdf-syntax-ns#"
xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
<RDF:Seq about="urn:mozilla:package:root">
<RDF:li resource="urn:mozilla:package:helloworld"/>
</RDF:Seq>
<RDF:Description about="urn:mozilla:package:helloworld"
chrome:displayName="Hello World"
chrome:author="Brian Duff"
chrome:authorURL="http://modev.dubh.org/helloworld"
chrome:name="helloworld"
chrome:extension="true"
chrome:description="A simple demonstration firefox extension.">
</RDF:Description>
<RDF:Seq about="urn:mozilla:overlays">
<RDF:li resource="chrome://browser/content/browser.xul"/>
</RDF:Seq>
<RDF:Seq about="chrome://browser/content/browser.xul">
<RDF:li>chrome://helloworld/content/helloworld-Overlay.xul</RDF:li>
</RDF:Seq>
</RDF:RDF>
这个文件的重要部分(也是每个扩展需要改变的部分)用粗体显示出来。我们为扩展提供了一个包(package)。这个包就使这个扩展与其它扩展区别开来,在这里我们选择helloworld包:
<RDF:Seq about="urn:mozilla:package:root">
<RDF:li resource="urn:mozilla:package:helloworld"/>
</RDF:Seq>
接下来,我们为这个扩展提供一个描述:
<RDF:Description about="urn:mozilla:package:helloworld"
chrome:displayName="Hello World"
chrome:author="Brian Duff"
chrome:authorURL="http://modev.dubh.org/helloworld"
chrome:name="helloworld"
chrome:extension="true"
chrome:description="A simple demonstration firefox extension.">
</RDF:Description>
下面,我们告诉mozilla产品的那个部分是我们需要扩展的。FireFox以及ThunderBird的所有的用户界面元素是通过一个称为XUL的界面定义语言描述的。这次界面元素被称为“chrome”。你可以扩展这两个产品的大多数可以部分。在这里,我们要扩展FireFox的浏览器主界面。定义为:
chrome://browser/content/browser.xul
<RDF:Seq about="urn:mozilla:overlays">
<RDF:li resource="chrome://browser/content/browser.xul"/>
</RDF:Seq>
现在我们已经描述了我们想扩展什么,我们需要提供一个XUL文件来将我们的自定义用户界面安装到浏览器窗口中。我们将在后面再一个helloworld-Overlay.xul文件中定义这些。我们必须告诉mozilla文件在什么地方以及它扩展了什么:
<RDF:Seq about="chrome://browser/content/browser.xul">
<RDF:li>chrome://helloworld/content/helloworld-Overlay.xul</RDF:li>
</RDF:Seq>
我们已经完成了创建扩展的第一步,下面的任务是定义我们要安装到主窗口中的用户界面元素。
Overlaying User Interface Elements
XUL是XML用户界面语言。XUL提供了一种称为 dynamic overlays 的结构,这种结构可以让你在不修改原始XUL文件的情况下修改窗口或者控件的用户界面元素。This way, the definition of extension user interface is de-coupled from the XUL files used to define the main interface elements in Firefox and Thunderbird。
我们开始创建 helloworld-Overlay.xul. 这个文件应该与 contents.rdf. 位于同一个目录。
<?xml version="1.0"?>
<overlay id="helloworldOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<menupopup id="menu_ToolsPopup">
<menuitem label="Hello World" position="1" />
</menupopup>
</overlay>
这个简单的范例在Tools菜单的顶部创建了一个“Hello world”的菜单项。我们的菜单项定义在了menupopup元素中。在XUL中,menupopup表示了一个菜单项的容器,例如一个弹出菜单或者一个主菜单的下拉项,我们在menupopup中放置了一个id为menu_ToolsPopup的菜单项。这个menu_ToolsPopup,在browser.xul中定义并且对应Tools菜单的下拉部分。
Creating an Install Manifest
最近版本的FireFox以及Thunderbird包含了一个新的扩展管理工具,这个工具可以轻松的安装和管理扩展。要告诉扩展管理工具关于你的扩展的一些信息,你必须写另外一个RDF文件叫做install.rdf。这个文件应该位于contents目录同级的位置中:
c:\myextensions\
+- helloworld
+- install.rdf
+- content
+- contents.rdf
+- helloworld-Overlay.xul
下面是安装的清单文件:
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/<chsdate year="1999" month="2" day="22" islunardate="False" isrocdate="False" w:st="on">1999/02/22</chsdate>-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:name>Hello World</em:name>
<em:id>{<chmetcnv w:st="on" unitname="a" sourcevalue="12" hasspace="False" negative="False" numbertype="1" tcsc="0">12a</chmetcnv>1584b-2123-473d-8752-e82e74e3cb1b}</em:id>
<em:version>0.1</em:version>
<em:targetApplication>
<Description>
<em:id>{ec<chmetcnv w:st="on" unitname="F" sourcevalue="8030" hasspace="False" negative="False" numbertype="1" tcsc="0">8030f</chmetcnv>7-c<chmetcnv w:st="on" unitname="a" sourcevalue="20" hasspace="False" negative="False" numbertype="1" tcsc="0">20a</chmetcnv><chmetcnv w:st="on" unitname="F" sourcevalue="464" hasspace="False" negative="True" numbertype="1" tcsc="0">-464f</chmetcnv>-9b0e<chmetcnv w:st="on" unitname="a" sourcevalue="13" hasspace="False" negative="True" numbertype="1" tcsc="0">-13a</chmetcnv><chmetcnv w:st="on" unitname="a" sourcevalue="3" hasspace="False" negative="False" numbertype="1" tcsc="0">3a</chmetcnv>9e97384}</em:id>
<em:minVersion>0.9</em:minVersion>
<em:maxVersion>1.0</em:maxVersion>
</Description>
</em:targetApplication>
<em:file>
<Description about="urn:mozilla:extension:file:helloworld.jar">
<em:package>content/</em:package>
</Description>
</em:file>
</Description>
</RDF>
首先,我们提供一个扩展的描述。这些描述信息会显示在Firefox的扩展管理工具中:
<em:name>Hello World</em:name>
<em:id>{<chmetcnv w:st="on" unitname="a" sourcevalue="12" hasspace="False" negative="False" numbertype="1" tcsc="0">12a</chmetcnv>1584b-2123-473d-8752-e82e74e3cb1b}</em:id>
<em:version>0.1</em:version>
在em:id部分中的内容是全局唯一标示(GUID)。这个GUID的目的是为了将你的扩展与其它扩展区分开来。当你在编写你自己的扩展时,你总要为每个单独的扩展产生一个新的GUID。Hoskinson提供了一个GUID generator web service。可以用它来产生GUID。
下面,我们描述我们要扩展哪个应用程序:
<em:targetApplication>
<Description>
<em:id>{ec<chmetcnv w:st="on" unitname="F" sourcevalue="8030" hasspace="False" negative="False" numbertype="1" tcsc="0">8030f</chmetcnv>7-c<chmetcnv w:st="on" unitname="a" sourcevalue="20" hasspace="False" negative="False" numbertype="1" tcsc="0">20a</chmetcnv><chmetcnv w:st="on" unitname="F" sourcevalue="464" hasspace="False" negative="True" numbertype="1" tcsc="0">-464f</chmetcnv>-9b0e<chmetcnv w:st="on" unitname="a" sourcevalue="13" hasspace="False" negative="True" numbertype="1" tcsc="0">-13a</chmetcnv><chmetcnv w:st="on" unitname="a" sourcevalue="3" hasspace="False" negative="False" numbertype="1" tcsc="0">3a</chmetcnv>9e97384}</em:id>
<em:minVersion>0.9</em:minVersion>
<em:maxVersion>1.0</em:maxVersion>
</Description>
</em:targetApplication>
每个Mozilla下的可扩展应用程序都有一个自己的GUID:你必须在这里正确的指定你所要扩展的程序的那个GUID。在本例中,我们使用FireFox的GUID。我们同时描述这个扩展可以工作的Firefox的最低和最高版本。
最后,我们告诉扩展管理工具需要安装的文件。下面,我将介绍如何将扩展打包以便可以自动安装到Firefox中:
<em:file>
<Description about="urn:mozilla:extension:file:helloworld.jar">
<em:package>content/</em:package>
</Description>
</em:file>
Packaging an Extension Installer
我们的扩展现在已经完成了。但是为了让用户可以更容易的安装它,我们需要将它打包以便Firefox安装。我们需要将上面的文件打包到一个XPI(Cross platform installer)文件中。一个XPI文件就是一个普通的zip 文件。我们的XPI文件的结构如下所示:
helloworld.xpi
+- install.rdf
+- chrome/
+- helloworld.jar
helloworld.jar是另外一个包含我们创建在content目录中所有文件的zip文件。
helloworld.jar
+- content/
+- contents.rdf
+- helloworld-Overlay.xul
通过上面的信息,我们可以通过zip工具创建helloworld.xpi。另外,你也可以通过类似Ant这样的build工具来编译这些文件,下面是我使用的Ant build文件:
<?xml version="1.0"?>
<project name="helloworld" default="createxpi">
<target name="createjar">
<zip destfile="helloworld.jar" basedir="."
includes="content/**" />
</target>
<target name="createxpi" depends="createjar">
<zip destfile="helloworld.xpi">
<zipfileset dir="." includes="helloworld.jar"
prefix="chrome" />
<zipfileset dir="." includes="install.rdf" />
</zip>
</target>
</project>
如果创建了名称为build.xml的build文件并且将它放到与install.rdf同级的目录中,你可以直接运行ant来创建.xpi文件。当创建xpi文件后,你可以在Firefox的File->Open中安装这个扩展。
<shape id="_x0000_i1026" style="WIDTH: 298.5pt; HEIGHT: 220.5pt" type="#_x0000_t75" alt="Hello World item in the Firefox Extension manager"><imagedata src="file:///C:%5CDOCUME~1%5C%E9%99%88%E9%94%90%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image002.gif" o:href="mhtml:file://E:\FireFox\Duffblog%20Writing%20an%20Extension%20for%20Firefox.mht!http://www.dubh.org/jdevimages/ff_hello_extman.png"></imagedata></shape>
Download the source code (24KB ZIP file).