為 Firefox OS 打造 Firefox 瀏覽器 (上)
在你聽著 Mozilla 眉飛色舞的提及「Firefox OS」這麼久,你是否知道當初建構 Firefox OS 的概念與過程呢?我們透過 Ben Francis 輕鬆說故事的口吻,讓大家能初步了解期間發生的許多小插曲。全篇將大略分成建構前的發想、開發過程,以及未來版本的走向。快來看看 Firefox OS 背後曾經的「愛恨情仇」吧!
在 2011 年 7 月宣佈啟動 Boot to Gecko (B2G) 專案之後,我心裡就認為自己找到能貢獻一己之長的東西了。我心中琢磨著「以 OS 為架構的瀏覽器」的想法已有一段時間。當時 Mozilla 雖然有人力,但相關技術力與影響力似乎還欠整合。
Mozilla 在當時並未很積極的號召大家開發 B2G,且團隊仍是四名發起人,整個專案雖然不是全然空白的 GitHub repository,但實質的東西卻也不多。而我在宣佈日隔天,就透過 Skype 和 Chris、Andreas、Mike 展開對話,也動身前往矽谷 (Silicon Valley) 短暫拜訪。我希望能說服他們讓我參與 (剛開始是約聘身分),如此我就能全心投入專案。
用 Web 技術打造的網路瀏覽器
Chris Jones 在我到職第一天就說「這個最高優先度的專案,就是最基本的網路瀏覽器,現在我要有『網址列』和『回到上一頁』按鈕就好。」
這個團隊當時完全使用 Web 技術,負責打造手機的使用者介面 (UI) 原型 ─「Gaia」。部分人員必須檢驗 Gaia 確實可行,另外還有人要找出 Web 平台的缺漏,並設法透過新的 Web API 補足這些缺漏。我當時就負責建構瀏覽器、相機、圖庫等 App 的第一原型,亦必須補上相關不足之處。
你可能會想問「為何以瀏覽器為架構的作業系統,還需要瀏覽器 App 呢」?當初對此原型的發想,是考量到「其他智慧型手機平台都有瀏覽器 App。而考量到使用者的習慣,B2G 當然也應該提供」。
Firefox 桌機版的 UI,就是以使用了 XUL 標記語言 (Markup language) 的特殊「chrome」程式碼撰寫而來。B2G 的 UI 則單純使用了 HTML、CSS、JavaScript;這點與其他 App 相同。
一切都是從
一切都是從 iframe 開始的:可用於網址列的文字輸入功能,再加上一個「Go」按鈕。你可到這裡觀看第一筆「commit」。在點擊「Go」按鈕時,就會針對文字輸入的內容,設定 iframe 的 src 屬性,也就會讓 iframe 載入該網址的網頁。
要以 iframe 建構瀏覽器時遇到的第一個問題,就是 JavaScript 中的同源政策 (Same-origin policy)。如果網頁內容與瀏覽器本身的來源 (Origin) 不同,則同源政策將阻止你存取 iframe 內的任何動靜;特別是 contentWindow 屬性及其內的所有資訊,均無法存取。為了建構全功能的瀏覽器,我們必須讓 Privileged App 能在跨源 (Cross-origin) 限制下,安全的開個後門以取得作業時的必要資訊,卻又不致造成嚴重的安全問題或影響到使用者的隱私。
而我們很快又遇上另一個問題,就是許多網頁作者會無所不用其極的防止自己的網站遭他人以 iframe 嵌入,進而避免受到網路釣魚攻擊。網路伺服器可傳送 X-Frame-Options 這個 HTTP 回應標頭,以告知瀏覽器不要在 iframe 中顯示內容,而且另有多樣「framebusting」技術,讓網站可主動反制 iframe 的嵌入,使其在外層頁框中載入網站本身。
我們很快就發現:想要不牽涉 Web 技術本身,卻要用 Web 技術打造瀏覽器是不太實際的事情。
Browser API
我在 2011 年 12 月的台北 Work Week 上遇見了 Justin Lebar。他當時負責修改 Gecko,設法將 Boot 上的瀏覽器帶入 Gecko。對我來說,Gecko 曾經是 (目前大略上仍可算是) 由魔法咒語組成的大型黑盒子。只要把我寫的程式碼丟進去,就會轉化成螢幕上跳動的圖像。我需要已能掌握某些咒語的魔法師幫我;尤其是「Docshell」這個特別強大的魔法,只有最老練的魔法師才能稍窺一二。
當我跟 Justin 說明我需要的東西時,他給我的回應就像是「車子送修的費用還不如乾脆換一台新車」。Justin 一直對我提出的需求湧現出更好的想法。但當時我們兩個根本無法預估手邊作業的規模大小。
在將簡單的「mozbrowser」布林 (Boolean) 屬性加入 Gecko 的 HTML iframe 元素之後,就誕生了 Browser API。我試著為瀏覽器 App 添增功能,只要發現目前 Web 技術所辦不到的,我就回頭找 Justin 再變出新的咒語出來。
另外有幾個比較輕鬆的方式可建構瀏覽器 App。新增機制可讓瀏覽器插入指令碼至 iframe 中,並自由溝通其網頁內容。但我們也想提供安全的 API,讓任何人都能打造自己的瀏覽器 App,不過這種想法風險太大。因此,我們在 DOM 中明確訂定 Privileged API 以提供一種新的 iframe,希望有一天能成為新的標準 HTML 標籤。
將 Web 包起來
我們先嚐試在 iframe 中載入網頁,但又要讓網頁以為自己不是在 iframe 之中。最開始的解決方案,是在具備 mozbrowser 屬性的安全名單網域中,針對 iframes 忽略 X-Frame-Options 標頭。但有時我們發現某些網站聰明到會跳出 iframes 之外。最後我們會讓 window.top 指向 iframe 本身而非其「parent」,讓網站不會發現自己具備「parent」,最後讓所有瀏覽器分頁各自於自己的系統程序中獨立執行。
一旦用 Web 圍住這隻動物之後,還是必須留個可呼吸的通風口。某些資訊仍須以「事件」的形式送出 iframe 之外,例如當更改網頁的位置、標題、圖示 (locationchange、titlechange、iconchange) 時;當網頁開始/結束載入作業 (loadstart、loadend) 時;當目前已載入網頁的安全特性變更 (securitychange) 時。這些情形都可即時反應於網址列與標題列之上,並顯示進度指示器。
瀏覽器 App 必須能告知 iframe 要 goBack()、goForward()、stop()、reload(),進而能瀏覽 iframe。我們也必須要能清楚要求如歷史紀錄 (getCanGoBack()、getCanGoForward() 等) 的特性,才能決定所要顯示的瀏覽按鈕。
在這些基礎要素都到位之後,就能建構簡易功能的瀏覽器 App 了。
原型
負責 Gaia 專案的首位使用者經驗 (UX) 設計師就是 Josh Carpenter。在 2012 年 2 月的世界行動通訊大會 (MWC) 之前,我們先在巴黎舉辦了一場 Work Week。當時 Josh 就針對智慧型手機的基本功能設計出 UI 模型,其中也包含了簡易的瀏覽器。我們也根據這些設計打造了原型。
瀏覽器 App 原型即可瀏覽網頁內容、將網頁包在 iframe 內,並顯示即將瀏覽內容的基本資訊。下方就是在當年 MWC 上展示的版本。
建立團隊
2012 年 5 月,我在高通 (Qualcomm) 位於聖地牙哥的辦公室參加了 Work Week,當時展示了更成熟的基本版瀏覽器 App,並是在 Firefox 桌機版之中執行。但這個版本仍算十分陽春。我們需要一個團隊開始打造完整 App 並足以安裝於實際裝置上。
我也在聖地牙哥第一次見到了 Dale Harvey。這位勇敢的蘇格蘭戰士將加入 Gaia 的行列。他的第一個任務就是必須協助打造瀏覽器 App。
Dale 首要進行的諸多任務之一,就是為瀏覽器添增多個分頁,甚至要幫 Browser API 加上「截圖」咒語,以顯示瀏覽器分頁的縮圖 (就跟你說他很勇敢吧)。
這時我們也開始向 Firefox 團隊商借其中一位才華洋溢的 Larissa Co 設計師,負責互動設計的部份;另外還有之前待過黑莓公司 (RIM) 的 Patryk Adamczyk,負責 B2G 上的瀏覽器視覺設計。從此時才真正開始有 Firefox 瀏覽器的外觀。
突然蹦出來的東西
網頁很喜歡用彈出視窗呈現別的內容。最常見的就像 alert()、prompt()、confirm()等。有時候會 open() 新的瀏覽器視窗 (並可再次 close())、用 _blank 視窗開啟連結、向你詢問密碼或授權進行某個作業、要求你選擇選單中的項目、開啟右鍵選單,或確認要重新寄送表單的內容。
上述這些都需要 Browser API 中的新事件,也都代表 Justin 必須想出更多咒語才能達成。
看到這裡,你是否了解 Firefox OS 誕生之初的概念呢?可別錯過後續的《(中)》與《(下)》篇,把整個有趣的故事看完吧!
原文連結:Building the Firefox browser for Firefox OS