2012年9月6日 星期四

FireBreath 心得

2017/10/13 敬告: FireBreath 在非 Windows 平台上所依賴的 NPAPI 已經被各大主流瀏覽器廢棄、禁用。因此 FireBreath 的開發也已暫停 (估計不可能再開)。此處心得只能留作回憶。

前言


FireBreath 是 2009 年才開始的開源專案, 旨在提供一個瀏覽器插件 (Broswer Plugins) 的抽象層, 把不同瀏覽器插件的實作方式包裝起來, 開放統一後的開發框架給所有的插件開發者. 如此一來要寫一個所有瀏覽器通吃的插件就能簡單一些, 至少可以專注在內容和功能的開發上, 不用擔心與各個瀏覽器接合的問題.



插件和擴展的差異


瀏覽器插件 (Plugins) 這個詞常會跟瀏覽器擴展 (Extensions) 有所混淆. Plugins 是用來協助瀏覽器詮釋或呈現特定 MIME 形式的網頁內容. 而 Extensions 則是在瀏覽器的外觀或界面上, 亦或行為上做出一些延伸或補充. 後者不在這裡的討論範圍. 如要對瀏覽器加上什麼有趣的功能時, 一定要先搞清楚你要開發的是插件還是擴展以免研究錯方向. 詳細的描述請見 Wiki 說明.

Plugin API 的兩大規格陣營 - ActiveX 和 NPAPI/PPAPI


最早的瀏覽器插件觀念是由 Netscape 引入的, 它們在自己的 Netscape Navigator 瀏覽器上實現了一組 API, 讓開發者可以自由替瀏覽器添加新的內容詮釋功能, 這個規格就是所謂的 NPAPI (Netscape Plugin API). 目前除了 IE 之外的瀏覽器 (如 Firefox, Opera, Safari, Chrome 等等) 都是吃這種規格的 Plugins. 而 IE 只在早期的 5.5 版本有支援 NPAPI Plugins, 隨後的版本就只支援自家的 ActiveX Plugins. 雖然 IE 不合群, 但因擁有廣大的市佔率, 所以用 ActiveX 開發的 Plugins 也不在少數, 因而形成了對立的局面. 在 FireBreath 出現之前, 若想要開發一個在所有瀏覽器上都能跑的插件, 就必需同時開發 ActiveX 和 NPAPI 兩種規格的版本.

額外一提的是 PPAPI, 它是由 Google 提出的一個衍生自 NPAPI 的後續規格, 目前只有實作在 Google 自己的 Chrome 瀏覽器上. Google 在 Chrome 上基於這個加強版的 PPAPI 接口規格, 實作了所謂的 NaCl (Native Client) 軟體開發框架. 並且也公開了 Native Client SDK, 方便開發者以開發一般軟體的開發經驗來開發網頁應用程式 (最終還是會以 Plugin 的形式被瀏覽器載入運行).

FireBreath 大致使用方式


(以我的 Windows 工作環境為例, 但 FireBreath 內部使用的第三方函式庫和工具幾乎都是跨平台的, 因此在 Linux 或 Mac 上也有非常類似的使用方式)

  1. FireBreath 的編譯工具需要使用到 git, cmake 和 Python. 官方有明述 Python 不可使用 3.x 版本, 建議用 2.7.x. 要透過 FireBreath 進行開發, 首先要把這些工具裝起來, 並且都要確保他們位於 PATH 中隨時可用.
  2. FireBreath 在 Windows 上進行 ActiveX 規格的 Plugin 編譯時, 需要使用到微軟的 ATL 函式庫, 但是只有專業版的 Visual Studio 會隨附 ATL, 免錢的 Visual Studio Express 並沒有. 不過可透過安裝微軟的 WDK 來補足這部分, WDK 是免付費的開發套件, 除了 ATL 之外還可以得到 MFC 4.2 函式庫. 安裝 WDK 時切記要使用預設的安裝路徑, 這樣 FireBreath 在進行 cmake 時會自動抓到對的 ATL 路徑. 否則就必需手動添加路徑.
  3. FireBreath 的源碼包可在其官網 Download 頁面中找到. 下載後解開到任一路徑下, 以下假定為 c:\firebreath .
  4. 照著官網的指示用內建的 Python 腳本建立 Plugin 專案. 然後視使用的 IDE 開發環境的需求, 使用 c:\firebreath 底下 prepXXXX.cmd/sh 的命令來產生可建構的專案檔. 它實際上是一個 batch file/shell script, 會利用 cmake 強大的各種 generators 來產生各目標 IDE 的專案檔. 第一次執行 prepXXXX 命令時需要可連線的網路環境, 它會自動透過 git 下載需要的 Boost 函式庫.
  5. 關於 FireBreath 的檔案分佈的大原則是: 所有透過 Python 腳本的 Plugin 專案都位於 c:\firebreath\projects\{專案名稱} 當中 (後稱專案目錄), 絕大部分你要寫的邏輯也都發生在這. 而所有 prepXXXX 產生的建構專案, 以及建構時的臨時檔案和最終檔案都會擺放在 c:\firebreath\build 底下, 若用 cmake 產生出 VC 的 solution 文件也會被放在這, 可以透過開啟這個 solution 編輯源碼檔案, 但不可直接在 solution 中調整專案的參數, 不然下次由 cmake 產 sln 時又會被蓋掉, 若有需要的話應該要改專案目錄底下的 CMakeLists.txt. 不熟悉 cmake 的人可能要花些時間摸一下, 不過 cmake 是跨平台建構的大勢所趨, 多摸不吃虧.
  6. 若試著自行做一些練習之後會發現, 決大部分的寫作會發生在專案目錄中的 {專案名稱}.cpp 和 {專案名稱}API.cpp 這兩個檔案中, 前者的作用是繪製內容, 也是插件的主要進入點. 後者是插件與瀏覽器事件的膠水層, 所有使用者的輸入事件都會透過這裡傳進 Plugin 中, 在這裡做對應的處理. 細節可參考 FireBreath 隨附的兩個 examples.
  7. 視各 IDE 開發環境而異, 開啟產生的專案檔然後執行建構 (Build), 輸出會在 build/bin/{專案名稱}/ 底下. 形式應為動態函式庫 (win: dll, linux: so, mac: dylib). 在非 Windows 系統中, 只要將該輸出放置到各瀏覽器明定的路徑 (檔名視瀏覽器的需求可能會要更改過) 就應該能被掛起. 而在 Windows 上需要靠相應的 Registry 登錄才能被認到, 詳見"Windows 上的小細節"
  8. 在建構專案時 FireBreath 會產生一個用來測試用的網頁來帶起你的 Plugin, 位置在 c:\firebreath\projects\{專案名稱}\gen\FBControl.htm . 用瀏覽器來開啟這個網頁就可以帶起你的 Plugin.


Windows 上的小細節


  1. 在 Windows 上 FireBreath 的輸出 dll 很巧妙的建構成既符合 ActiveX 控制項的界面, 同時又提供 NPAPI 界面的二合一共構形態. 此外, IE 和某些瀏覽器如 Firefox 是仰賴 Registry 中登錄的資訊來查找 Plugins 的, FireBreath 很巧妙的透過 ActiveX 控制項的自我登錄 (Self Register) 功能將 IE 和 Firefox 所需要的登錄資訊都一併填寫在 DllRegisterServer() 接口中. 在為 IE 進行 ActiveX Plugin 登錄的過程中也一併完成 Firefox 的 Plugin 登錄.
  2. 替 IE 登錄 ActiveX Plugin 的方法為使用 regsvr32 c:\path\to\plugin\npXXXXXX.dll (即一般 ActiveX 控制項共通的註冊方式). 注意 regsvr32 /u c:\path\to\plugin\npXXXXXX.dll 並不會清除 Registry 中於註冊時填入的內容. 這是因為 ATL Register Script 中預設是只寫不刪, 詳見後述.
  3. FireBreath 有提供一些預設樣版用以決定要在 Registry 中填入什麼東西. 這些樣版的位置在 c:\firebreath\gen_templates 中. 它們的副檔名是 .rgs, 實際上是微軟 ATL Registry Script的形式. 若要修改裡面的內容, 請依 FireBreath 的指示, 複製一份到你的專案目錄中, 而不要改位於 gen_templates 目錄中的內容, 以避免影響到其它專案.
  4. 如前述, FireBreath 預設是在註冊 ActiveX 控制項時, 同時註冊 Firefox Plugin. 若有任何理由想要修改為只註冊一種規格, 可透過上述方式修改 FBControl.rgs 的內容. 很明顯此檔案內前半段是描述 IE ActiveX Plugin 登錄事項, 後半部是 Firefox 的, 看你要移除哪一邊.
  5. 若要調整反註冊時 (即 regsvr32 /u 時) 的行為成會清除部分或全部的相關 Registry. 請試著移除 FBControl.rgs 中 NoRemove 的關鍵字, 以及上 MSDN 了解 NoRemove 關鍵字.
  6. 註冊 ActiveX 控制項時, 預設是註冊在 HKCR (即 HKEY_CLASSES_ROOT) 中. HKEY_CLASSES_ROOT 實為 HKEY_CURRENT_USER 和 HKEY_LOCAL_MACHINE 其下的 Software/Classes 聯合映射. 簡言之, 就是寫入 HKCR 後最後很可能會被寫到 HKLM 裡面, 變成是替所有本地電腦的使用者都註冊了這個 ActiveX Plugin. 若這不是你想要的, 而是想只針對目前使用者註冊的話, 也請修改兩個 .rgs 檔, 把 HKCR 的部分都改為 HKCU (HKEY_CURRENT_USER). 另外把要寫的內容內縮兩層到 Software/Classes 底下. 文件中有個 ${REGKEY_ROOT} 的變數實際上也是指到 HKCU.


運作方式以及除錯方式


Plugin 的除錯有點麻煩, 本質上就是除錯單一 dll 的難度. 你必需先運行它的宿主, 也就是瀏覽器, 等宿主確定截入 dll 之後, 再要求 Debugger 用 Attach 的方式 Attach 上宿主的 process 進行除錯. 過程中有一些眉角, 這裡用 Chrome 為例說明一下:

  1. 依照 這裡的建議, 關閉所有的 chrome, 然後從 command line 中執行 chrome.exe 附上 --plugin-startup-dialog 的參數. 再由這個 chrome 去開啟 FBControl.htm. chrome 會在載入 plugin 之後, 實際執行之前, 跳出一個視窗顯示自身的 PID 並且等候 Debugger Attach. 這時再要求 Visual Studio 用 Attach 的方式連上 PID 進行 Debugging (VS中要保持 FireBreath 專案開啟的狀態, 可以直接下斷點)
  2. 若是用 Visual Studio Express 版本, Attach 的功能基本上是被移除掉的. 可以試試看這個網友提供的作法, 建立一個空專案, 然後直接竄改內容讓它進行 Debug 時, 實際上是帶起一個你任意指定的程式. 把那個程式設定為 chrome 然後要它去開 FBControl.htm 即可.

沒有留言:

張貼留言