我的firefox插件开发历程

https://addons.mozilla.org/en-US/developers/docs/reference

首先给出firefox插件开发的官方文档列表,如果没有列表,那么开发firefox插件几乎不可能,光看中文资料也是会死的说,从老大给了任务,到基本完成任务,中间花了一周时间,这一周是痛苦而又极有成就感的一周,我的插件其实功能还算简单,就是在界面上添加一个按钮,点击按钮打开我们的主页,右键菜单上在加上一个菜单项,点击可以把当前页面存到我们的server上(HTTP接口)

开发环境:ubuntu10.10 firefox 7.0


基础知识:

firefox插件是一个xpi文件,例如firefox-thinkernote.xpi,安装方式有两种,前者直接拖拽到地址栏,就会提示你安装,再者选择菜单:工具/附件管理 打开附加组件管理窗口,窗口右上侧的搜索栏前有一个扳手的图标,点击选择从文件安装附加组件,就会打开一个选择窗口,找到咱的xpi所在目录,点击即可,也会提示咱们安装

xpi文件其实就是一个zip文件,把我们的开发目录压缩成一个zip压缩包,再重命名就是我们的安装插件了,而我们的插件开发目录其实是有要求的:

firefox-thinkernote/

  chrome/

    overlay.xul

    overlay.js

  locale/

   en-US/

    overlay.dtd

   zh-CN/

    overlay.dtd

  skin/

    classic/

    icons/

      overlay.css

  install.rdf

  chrome.manifest

顶层目录没有要求,叫什么都成,我叫这个名字是表示这个插件是我们项目的firefox插件,不过底下的结构就有要求了,install.rdf是一个XML文件,描述的插件的开发者信息,谁开发的插件,插件版本,不过需要注意的是:targetAppliction/Description/em:id必须是{ec8030f7-c20a-464f-9b0e-13a3a9e97384}这个表示,该插件是为firefox浏览器开发。另一个em:id 则用于描述插件ID,所以该ID也不能重复,你想很多插件装在一个浏览器上,浏览器怎么区分,必须有一个不重复的ID,因此这个ID可以取邮件地址,因为邮件是全世界唯一的,或者取GUID,这个我不懂,所以我取邮件地址作为插件ID

<?xml version="1.0"?>



<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"

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



    <Description about="urn:mozilla:install-manifest">

        <!-- 指出扩展的ID。该ID应该是一个Email格式的字符串,或者是一个GUID。注意,使用Email的作用是保证该ID的唯一性,并不要求这个Email地址是有效的。必填。 -->

        <em:id>[email protected]</em:id>

        <!-- 指出插件的版本号。必填。 -->

        <em:version>1.0</em:version>

        <!-- 在这里的值必须是2。该标签说明该应用的Firefox扩展,而不是其他XUL应用程序。Firefox插件的代码是2,如果是Firefox主题则会是4。必填。 -->

        <em:type>2</em:type>

        

        <!-- 安装扩展的目标应用程序以及最高版本和最低版本。必填。 -->

        <em:targetApplication>

            <Description>

                <!-- Firefox的ID,这个值不能改变。必填。 -->

                <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>

                <!-- 指明能使用该扩展的Firefox最低版本。这里是指1.5。必填。 -->

                <em:minVersion>1.5</em:minVersion>

                <!-- 指明能使用该扩展的Firefox最高版本。这里是指3.0.x。结合minVersion,即是说本扩展只适用于1.5和3.0.x之间的版本。必填。 -->

                <em:maxVersion>10.0</em:maxVersion>

            </Description>

        </em:targetApplication>

        

        <!-- 扩展的元数据。 -->

        <!-- 扩展名字。必填。 -->

        <em:name>ThinkerNote</em:name>

        <!-- 扩展的描述。这里的描述将出现在Firefox的工具-附加组件的描述栏。选填。 -->

        <em:description>thinkernote 行客记事</em:description>

        <!-- 扩展作者。选填。 -->

        <em:creator>thinkernote.com</em:creator>

        <!-- 扩展主页的URL。选填。 -->

        <em:homepageURL>http://www.thinkernote.com/</em:homepageURL>

    </Description>            

</RDF>

chrome.manifest 定义开发包名称和资源位置的,其语法是

directoryName  packageName  positionInDirectoryOfPackage

content        thinkernote                chrome/content/

locale         thinkernote     en-US         chrome/locale/en-US/

skin        thinkernote        classic/1.0    chrome/skin/classic/

overlay        chrome://browser/content/browser.xul            chrome://thinkernote/content/overlay.xul

style        chrome://global/content/customizeToolbar.xul    chrome://thinkernote/skin/overlay.css

overlay        chrome://browser/content/browser.xul            chrome://thinkernote/content/overlay.xul

这一行是说把我们的xul文件追加到系统的xul里去,浏览器在启动的时候会启动browser.xul也会顺道启动我们的overlay.xul,这样我们的插件就和浏览器一起启动,并能做一些事情了,注意我们定义了content目录以后,就可以通过chrome://packageName/directoryName/fileName来引用文件了,例如overlay.xul其实是在 firefox-thinkernote/chrome/content/下面

xul文件也是一个XML文件,它描述的是我们的插件启动以后,界面是什么样的,不过大多数的插件没有界面只是在工具栏增加了按钮,右键菜单增加了菜单项

<?xml version="1.0"?>

<?xml-stylesheet href="chrome://thinkernote/skin/overlay.css" type="text/css"?>

<!DOCTYPE overlay SYSTEM "chrome://thinkernote/locale/overlay.dtd">



<overlay id="thinkernoteOverlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

  <script type="application/x-javascript" src="chrome://thinkernote/content/jquery.min.js"/>

  <script type="application/x-javascript" src="chrome://thinkernote/content/common.js"/>

  <script type="application/x-javascript" src="chrome://thinkernote/content/common_net.js"/>

  <script type="application/x-javascript" src="chrome://thinkernote/content/overlay.js"/>

  <script type="application/x-javascript" src="chrome://thinkernote/content/domtohtml.js"/>

  <script type="application/x-javascript" src="chrome://thinkernote/content/action.js"/>



  <menupopup id="menu_ToolsPopup">

    <menuitem id="thinkernote-menubutton" insertafter="devToolsSeparator" label="&thinkernote.label;" oncommand="gotoHomePage()"/>

  </menupopup>

  

  <popup id="contentAreaContextMenu">

    <menuitem id="thinkernote-context" image="chrome://thinkernote/skin/icons/16x16.png" label="&thinkernote.desc;" insertafter="devToolsSeparator" class="menuitem-iconic" oncommand="doAction()"/>

  </popup>



  <toolbarpalette id="BrowserToolbarPalette">

    <toolbarbutton id="thinkernote-toolbarbutton"

           class="toolbarbutton-1 chromeclass-toolbar-additional"

           oncommand="gotoHomePage()"

           label="&thinkernote.label;"

           tooltiptext="&thinkernote.label;" />

  </toolbarpalette>

</overlay>

我们这个XUL文件是在chrome.manifest文件里指定的,让系统启动时加载的XUL文件,这里定义了菜单项,按钮,和右键菜单,他们的oncommnd事件和HTML里的onclick没有区别,意思就是说当它们被点击时取执行指定的函数。这些函数被定义在JS文件里,所以XUL文件的开头部分就定义了script引用(注意他们的src)OK,能引用JS就能引用CSS,CSS进来是干嘛的呢,他们来描述我们定义的按钮,例如按钮需要一张图片,他们就来告诉浏览器图片在哪里,那么怎么告诉呢?用按钮的ID,在CSS文件里定义一个和按钮ID名相同的CSS样式定义,系统会自己查找匹配

@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");



#thinkernote-toolbarbutton {

    list-style-image: url("chrome://thinkernote/skin/icons/24x24.png");

}



toolbar[iconsize="small"] #thinkernote-toolbarbutton {

    list-style-image: url("chrome://thinkernote/skin/icons/19x19.png");

}



#saveFormWindow{

    background-color:white;

}

OK,说了JS,CSS是干嘛的,那么DTD又是干嘛的呢,DTD其实是为国际化开发做准备,我们把各种语言的字符串放到不同的DTD文件里,定义如下,中间的部分是ENTITY-NAME,名字的thinkernote没有特殊的意思,就已名字的一部分而已,使用的时候就可以用"& ENTITY-NAME" 来引用

<!ENTITY thinkernote.label "行客记事">

<!ENTITY thinkernote.desc "保存到行客记事">

<!ENTITY title "保存到行客记事">

特别要说明一点的是,即便是在CSS样式里定义了按钮图片,DTD文件里定义了按钮文字,按钮还是不会出来,orz 因为我们还少了一步,用代码把按钮设置到工具栏上去

function installButton(toolbarId, id, afterId)

{

    if (!document.getElementById(id)) {

        var toolbar = document.getElementById(toolbarId);



        var before = toolbar.firstChild;

        if (afterId) {

            let elem = before = document.getElementById(afterId);

            if (elem && elem.parentNode == toolbar)

                before = elem.nextElementSibling;

        }



        toolbar.insertItem(id, before);

        toolbar.setAttribute("currentset", toolbar.currentSet);

        document.persist(toolbar.id, "currentset");

    }

}



    

function firstRun(extensions){

    let extension = extensions.get("[email protected]");

    var first = extension.firstRun;

    if(first){

       installButton("nav-bar", "thinkernote-toolbarbutton", "urlbar-container");

    }//第一次安装运行时first才等于true

}



var Application = Components.classes["@mozilla.org/fuel/application;1"].getService(Components.interfaces.fuelIApplication);



if (Application.extensions)

    firstRun(extensions);

else

    Application.getExtensions(firstRun);


JS的代码编写 


在编写页面的时候,我们会使用DOM对象来访问页面上的元素,例如document,window对象,因此如果要没这些可以直接拿来用的顶层全局对象整个就没法玩,因此我们要找在这个控件里可以直接拿来用的对象,我发现有两个对象gBrowser对象和document对象,gBrowser表示浏览器,document表示装载的页面,不过假设用户通过地址栏打开了baidu.com我们想访问这个页面还不能直接使用document对象,而是要这么获得

function getDocument()

{

    return document.getElementById('content').selectedBrowser.contentDocument;

}



function gotoHomePage()

{

    pageDocument = getDocument();

    pageDocument.location = serverUri;

}



function gotoLogin()

{

    gBrowser.selectedTab = gBrowser.addTab(serverUri + "/login"); 

}

 firefox插件资料比较少,baidu文档里有一些,如果您在看本文可以去看看,最重要的还是在于看官方的文档!

 

附免打包的开发环境配置

 


邮件地址作为ID:[email protected] 在firefox的插件目录下建立一个和邮件名同名的文件

$ cd .mozilla/firefox/g911mow7.dev/extensions

$ touch [email protected]

$ vi [email protected]

写入代码所在目录:/home/shujunli/firefox-thinkernote/

 

补充信息:

上次配置开发环境时查看的资料说需要建立一个dev的环境,然后找dev的extensions目录,其实这不是必需的的,实际上firefox在主目录生成了一个隐藏文件夹.mozilla 并且这个隐藏文件夹下有一个目录是用来放置安装插件的,在我的系统里这个目录是 ~/.mozilla/firefox/i7lsshse.default/extensions 在这个目录里能看见浏览器已经安装了的插件源码(每个源码是一个文件夹或者是email或者是uuid)按照上面描述的免打包开发环境的配置,在这个目录下放一个文本文件

 

 

你可能感兴趣的:(firefox)