firefox插件 firefox plugins mozilla windows linux
目錄(?)[+]
- Firefox插件plugins開發實用指南
- 如何對于plugin進行調試
原文:http://huandu.me/2010/02/11/595/
Firefox插件(plugins)開發實用指南
Firefox插件可實作強大功能,但其中麻煩事情不少。寫這個實用指南首先是為了友善自己記憶,免得以後再次栽倒一些坑裡面,如果能幫助其他人,則是更好。這個指南不是為了手把手教讀者開發插件,而是作為一個FAQ,解決各種詭異問題。
Firefox擁有衆多的擴充(Extension),開發擴充也非常容易,不過有一些事情還是無法用擴充解決,需要通路作業系統的底層功能,這就需要寫插件(plugins)。例如flash就是一個插件而不是擴充。
Mozilla提供了一系列的教程和文檔,雖然很不詳盡,衆多重要的API語焉不詳,但至少是一個好的開始。
最需要閱讀的是plugins API和使用入門。這是一個相當長的文檔,如果看完所有的内容會花費大量的時間而且還會很暈,這裡列一些重點供參考。
- plugins基礎概念
- 寫第一個插件(隻需要關注Writing Plug-ins這一節所談到的内容)
- 獲得一份firefox的源碼,比如firefox 3.6。plugins的例子可以在源碼裡找到(modules/plugin/sdk/samples),如果出了問題還可以自己編譯一個debug版的firefox來調試。
- 了解浏覽器能提供什麼功能
- 制作插件的安裝程式,推薦用擴充的方式安裝插件,有無數的好處
完成以上這些内容以後差不多就已經可以實作自己的插件了,一般而言,參照着例子來做開發不會有什麼問題,隻是有不少細節需要留意。
Firefox plugins開發的衆多奇怪的約定(假設plugins已經被正确安裝)
有些約定非常奇怪,不要問我為什麼,天曉得開發firefox的牛人們怎麼想的。
在Windows下,plugins必須滿足以下條件才能被firefox檢測到:
- 插件的名字必須是np*.dll,也就是必須以np開頭,.dll結尾
- 插件dll資源的語言必須為LANG_ENGLISH,code page必須為1252。在rc檔案裡是這麼寫的:
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252)
- 插件dll的VERSION_INFO裡面必須包含以下值:
這個MIME就是<object>标簽引用插件的唯一憑證。VALUE "MIMEType", "application/x-your-mimetype"
在Linux下,plugins必須滿足以下條件才能被檢測到:
- 插件的名字必須是lib*plugin.so,即以lib開頭,plugin.so結尾
- 插件必須實作NP_GetMIMEDescription和NP_GetPluginVersion,并傳回合适MIME字元串。注意,這個字元串并不是普通的MIME,是有特殊規則的,詳見前面這個連結的内容。
- 插件so不要靜态連結gtk、opensll、pthread、z等系統庫,這會在不同linux平台上因為符号表的問題遇到各種運作時錯誤
特别需要說明的是,NP_GetPluginVersion、NP_GetEntryPoints等關鍵函數沒有任何官方文檔介紹它們,隻能根據例子來猜,反正沒事就别改它們的實作,copy例子中的代碼就好。
firefox插件開發注意事項
寫firefox插件的一個基本習慣是,經常編譯代碼并運作它,保證你的插件還能工作。隻要firefox無法加載dll/so,或者加載出現任何錯誤,都會悄無聲息的忽略這個插件。時常關注一下about:plugins,看看插件是不是還在這個清單裡。
firefox插件從視窗模式上可分為windowless和windowed兩種。其中,windowless模式的文檔較多較全,是firefox比較推薦的模式,坑比較少,這裡就不多說了。windowed模式則相反,需要好好說說。
無論在Windows還是Linux上,windowed的插件都擁有獨立于浏覽器頁面的視窗。firefox會通過插件的NPP_SetWindow來告訴插件目前視窗的情況。
關于windowed插件有兩個詭異問題需要注意:
- Windows平台下,插件視窗預設會響應WM_CTLCOLOREDIT、WM_CTLCOLORLISTBOX、WM_CTLCOLORBTN、WM_CTLCOLORSTATIC消息,并設定一個預設的背景色。這本來沒問題,但在Windows XP下,這個顔色居然永遠是黑色,而不是預設系統背景色(通常是白色)。最好subclass這個視窗并且攔截這些消息,不要讓firefox去處理它們。對于插件來說,firefox處理這些消息隻是幫倒忙而已。至于firefox還幫了哪些倒忙,可以去源碼widget/src/windows/nsWindows.cpp的nsWindow::ProcessMessage()去圍觀。
- Linux平台下,NPP_SetWindow傳入的NPWindow指針中雖然有一個ws_info成員,這個成員裡面也确實有一個display變量指向X Window的Display結構,但絕對不要真正使用它,否則可能會導緻firefox直接退出,據說這可能是firefox的一個bug。
測試firefox插件小技巧,測試方面的高手可以無視
測試插件前建議先在firefox裡面建立一個新的profile(帳号)。這樣可以創造一個最幹淨的開發環境,避免被其他擴充/插件幹擾。
預設的profile名叫default,在指令行裡輸入
firefox -p default
就可以使用這個profile。如果隻是輸入
firefox -p
,會彈出一個對話框用于選擇profile。這個指令在Windows和Linux下都可使用。
無論是哪個平台,調試插件的方法都很類似。
Windows下可以用VC以調試方式啟動firefox,載入插件時調試器會自動載入對應的符号,捕捉發生的異常或者設斷點都很友善。
Linux下直接用gdb就好,細節應該不用多說。有一點需要注意,系統預設安裝的firefox指令(預設放在/usr/bin/firefox)是一個shell腳本,真正的可執行檔案名字需要打開這個腳本自行查找。
實作firefox插件的基本功能
firefox為插件提供的接口十分原始,很多功能預設沒有實作,下面提供了一些思路和方法。
- 讓插件接受焦點:預設情況下,<object>标簽不能獲得焦點,必須指定tabindex。
- 在插件中使用tab鍵跳到下一個element:沒有好辦法,必須自己手動将焦點還給浏覽器視窗(Linux下不必如此),然後自己用NPN_*系列函數找到應該獲得focus的DOM element,然後調用這個element的focus()方法。
- 隐藏和顯示插件:直接設定<object>标簽的style.display = “none”即可,但這裡有個嚴重的副作用,firefox會調用插件的NS_PluginShutdown,銷毀這個插件。如果不期望造成這種效果,要麼别用這種方式隐藏插件,要麼把插件狀态儲存在js裡,再次顯示的時候把狀态設回去。
- 觸發DOM事件:firefox沒有提供任何便利的方法觸發DOM事件,要在插件中做到這點,必須自己模拟js觸發DOM事件的過程。例如,對于HTML事件,假設self是DOM element,js會這麼做。
對應的C代碼就是evt = document.createEvent("KeyboardEvent"); evt.initKeyEvent( "blur", // in DOMString typeArg, false, // in boolean canBubbleArg, false); // in boolean cancelableArg, self.dispatchEvent(evt);
view plain copy to clipboard print ?
- void FireHTMLEvent(NPP npp, const string & name)
- {
- NPVariant result;
- NPObject *window;
- NPVariant vDoc;
- NPN_GetValue(npp, NPNVWindowNPObject, &window);
- // 也許頁面已經跳轉了……
- if (!window) {
- return;
- }
- NPIdentifier sDocument = NPN_GetStringIdentifier("document");
- NPN_GetProperty(npp, window, sDocument, &vDoc);
- NPN_ReleaseObject(window);
- // evt = document.createEvent("KeyboardEvent");
- NPVariant evt;
- NPObject* npDoc = NPVARIANT_TO_OBJECT(vDoc);
- NPIdentifier createEvent = NPN_GetStringIdentifier("createEvent");
- NPVariant eventArgs[1];
- STRINGZ_TO_NPVARIANT("HTMLEvents", eventArgs[0]);
- NPN_Invoke(npp, npDoc, createEvent, eventArgs, 1, &evt);
- NPN_ReleaseObject(npDoc);
- // evt.initKeyEvent(
- // "blur", // in DOMString typeArg,
- // false, // in boolean canBubbleArg,
- // false); // in boolean cancelableArg,
- NPObject * npEvt = NPVARIANT_TO_OBJECT(evt);
- NPIdentifier initKeyEvent = NPN_GetStringIdentifier("initEvent");
- NPVariant initArgs[3];
- STRINGZ_TO_NPVARIANT(name.c_str(), initArgs[0]);
- BOOLEAN_TO_NPVARIANT(false, initArgs[1]);
- BOOLEAN_TO_NPVARIANT(false, initArgs[2]);
- NPN_Invoke(npp, npEvt, initKeyEvent, initArgs, 3, &result);
- NPN_ReleaseVariantValue(&result);
- // this.dispatchEvent(evt);
- NPObject * self;
- NPN_GetValue(npp, NPNVPluginElementNPObject, &self);
- NPIdentifier dispatchEvent = NPN_GetStringIdentifier("dispatchEvent");
- NPVariant dispatchArgs[1];
- dispatchArgs[0] = evt;
- NPN_Invoke(npp, self, dispatchEvent, dispatchArgs, 1, &result);
- NPN_ReleaseVariantValue(&result);
- NPN_ReleaseObject(npEvt);
- NPN_ReleaseObject(self);
- }
暫時先寫到這裡,如果還有什麼疑難雜症,歡迎評論,我繼續添加。
如何對于plugin進行調試。
如firefox安裝路徑如下: C:\Program Files\Mozilla Firefox
1)在配置屬性/調試/指令, 設定為你的firefo.exe路徑:
C:\Program Files\Mozilla Firefox\firefox.exe
2)在配置屬性/正常/輸出目錄, 設定為:
C:\Program Files\Mozilla Firefox\plugins
3) 在配置屬性/生成事件/生成後事件/指令行, 設定為
copy "$(OutDir)\$(ProjectName).dll" "C:\Program Files\Mozilla Firefox\plugins\$(ProjectName).dll"
< 2和3任選其一 >
運作, 打開測試的htm, 就可以調試
樓上的方法現在應該行不通了。
我的環境是firefox 5, VS2008,斷點進不去,但是可以肯定調用的是我自己的插件。
目前我發現的調試插件dll的解決方法如下:
按照上述設定(也可以做成xpi安裝後,安裝目錄在appdata下一個檔案夾内,将插件放到那裡,隻要firefox能找到插件正常調用就好了)後,正常F5進入調試狀态,再attach到程序:plugin_container上,斷點就可以進入調試了。