2017年2月25日 星期六

Firefox WebExtension 入門 - 筆記 & 心得


緣起

  • Sleipnir 是日本人開發的瀏覽器,支援 IE 核心、免安裝、可設定很多熱鍵及滑鼠手勢,多年以來是用 2.99 版,因為第三版之後介面比較華麗(跑得比較慢)而且可以設定的項目反而變少。搭配的套件是 SeaHorse,也就是類似 Firefox 的 GreaseMonkey,用使用者自定的 JavaScript 去「後處理」網頁。一張爛圖可以用 Photoshop 修成好圖,爛網站也可以用 user script 修成好用的介面。
  • 因為用的是非常舊的版本,遇到較新版本的IE開始不是很相容,當然也有可能是院內網的問題,總之下定決心轉換跑道,希望用比較新的工具!
  • 剛開始嘗試寫成 Chrome 的 extension,但發現遇到的問題比 Firefox 多一些,於是又改寫成 Firefox 的 WebE xtension,還好後者本來就向前者致敬,不需要改很多東西。

背景知識

  • Firefox 以前的套件稱作 add-on,要查 add-on SDK;但每個頁面最上面都會提示你說這是舊的技術,建議改用 WebExtension
  • 最終的套件是用把所有檔案 zip 打包再改成 xpi 副檔名。在開發過程中,建議用Firefox Developer Edition,在 about:debug 頁面中可以直接 load 資料夾中的 manifest.json 作測試。
  • manifest.json 是整個套件最重要的檔案,包含這個套件的基本資訊、套件可以用到的權限、定義 content scripts 的 rules。很明顯的是一個 JSON 的結構。
  • content script 就是 user script,但rule是定義在 manifest.json 而不是在script 裡
    • matches:某個 script 要套用的網頁 URL 規則,要注意的是 URL 包含 scheme, host, path
    • run_at:通常等到網頁 loading 完才執行 script,但可以設定在 loading 完成前就執行
    • js:為了安全因素 content script 執行的 scope 是和網頁不同的,如果希望無痛轉移原本的 Sleipnir + SeaHorse,需要在 content script 中再把舊的 script 注入(inject)到網頁裡。
      • Chrome extension 的資料比 Firefox 多,詳見此篇必讀!
      • Content script 當作一種橋樑,一方面可以和套件的其他部分溝通,一方面可以和網頁溝通。
  • background script 是 Firefox 執行後就會在背景常駐的一個 script,作為一個中央指揮部,用來(暫時)儲存使用者的帳號/密碼、定時 refresh session id 以免被登出。這些功能本來是寫在背景執行的 AutoHotkey script,搭配 Sleipnir 開啟。
  • popup:容易誤解的名詞,是指(選擇性地)在右上角可以顯示一個圖示,按下圖示時會出現的框(事實上是一個網頁)
    • 要在 manifest.json 裡定義 browser_action
    • 網頁原始檔不能有任何 inline JavaScript,應該要用外部連結到另一個 js 檔(主要是 submit button 會用到)
  • popup、background script、content script 可以互相溝通,利用 browser.runtime.sendMessagebrowser.runtime.onMessage

結構

  • 啟動 firefox,預設首頁就是院內網登入頁;background script 直接開啟 popup,提示使用者輸入帳號/密碼
  • popup 用 http request 去檢查帳密能不能登入,如果登入成功,會將帳密傳給 background script 儲存,所以 firefox 還開著的時候都可以記憶帳密、快速登入
  • popup 也會 sendMessage 給開啟的登入頁的 content script,自動填入帳密;事實上,登入頁的 content script 會先向 background script 請求帳密,以達成自動登入
  • content script 可以指定數個 script 依序讀入,加上 content script 和 page script 是分開的,所以能 load 額外的 jQuery 或 jQuery UI,又不會和原本的網頁衝突
  • 針對 IE only 的網頁(例如需要用到 ActiveX 的頁面),裝了幾個類似 IE tab 的現成套件好像都沒有作用,目前先設計 content script 在 document_start 時就把網頁 title(會顯示在 firefox 的視窗 title)改成特定的文字(含 url),再由背景的 AutoHotkey script 去抓 title 中的 url,另外由 IE 開啟。當然,這招是很 low 的解法,還沒有考慮 cookie、session 等。

發佈/更新

  • manifest.json 裡的版本號更新,將所有檔案打包成 zip 檔
  • 套件中心登入,第一次上傳時,「如何散布此版本」選擇「您自行處理」,表示我要自己管理更新來源,而不是放在官方網站上,因為放在官網的套件需要人工審查,要排隊等.超.久!
  • 上傳後會自動審查,沒有重大錯誤就 OK 了,會提供簽章過的 xpi 檔,下載之(沒有簽章過的套件,是不能裝在一般 firefox)
  • 套件會抓 manifest.json 裡的 update_url 所連結的檔案(一定要 https 開頭的連結),格式也是 JSON,包含各版本的檔案連結;所以 updates.json 和 xpi 檔要放到一個網路空間(例如 dropbox),xpi 檔的連結寫進 updates.json,updates.json 的連結寫進 manifest.json
  • 整個發佈/更新流程可以用 web-ext 完成,但我還在研究中...