Facebook開發手記:新iOS應用的背后
Facebook是如何做iOS應用的?
Facebook上周發布了新版iOS應用。Facebook工程師Jonathan Dan在Facebook官方頁面中撰文,介紹了新版iOS應用,Facebook iOS應用的發展歷程以及開發思路。
我們今天(編者注:8月23日)發布了新版iOS應用,速度更快、更可靠、更易用。這款新應用標志著Facebook移動產品開發方式的轉型,即深耕不同平臺。為了便于你們理解這一轉型,讓我們回顧移動版Facebook的發展歷程。
Three20
早期的iPhone版Facebook誕生于iPhone的起步階段,當時還沒有iPad,而系統也不叫iOS。在早期版本中,我們開發了名為Three20的開源框架,其中包括當時系統尚未提供的組件庫。
在隨后幾年中,Three20成為iOS社區最流行的開源項目之一,幫我們解決了很多問題。然而隨著技術的發展,Three20逐漸顯得過時。其功能越來越復雜,對入門者來說上手變難。另一方面,隨著iOS核心的迅速發展,Three20的一些功能也顯得沒有太大用途。因此,最新版iOS應用是我們這么多年來首次沒有使用Three20框架。
基于HTML5的發展
隨著過去幾年移動設備的發展,我們最需要解決的問題是,無論你用什么設備、平臺、運營商網絡,甚至無論你在哪里,都應當獲得不錯的移動體驗。為了支持數千款手機和多個移動平臺,我們利用HTML5技術去開發移動版Facebook,并向包括iOS在內的多個平臺發布。
利用HTML5,我們只要進行一次開發,就可以向多個平臺發布產品。這樣做使我們能覆蓋盡可能多的用戶,也使Facebook移動業務發展到了當前的規模。實際上,我們選擇HTML5不僅是因為可以跨平臺使用一套代碼,也是由于這樣做有利于快速迭代,在不發布新版本的情況下測試新功能。
基于這一網頁技術,我們為5億Facebook移動用戶提供服務,并支持了7000多款設備。然而我們意識到,對iOS這樣的平臺來說,人們會希望更快、更可靠的體驗,而這正是我們iOS應用的不足之處。我們已經普及了移動服務,現在需要深耕服務。因此,我們從頭開始重寫了Facebook的iOS應用,專注于質量,并充分利用iOS系統自身這些年來的發展。
一切為了速度
開發原生iOS應用帶來了一個顯而易見的好處,就是應用的速度。在新版iOS應用中,動態匯總的滾動明顯更流暢,而具體實現方式則是對處理任務的系統資源進行更好的調度。例如在iOS中,主線程驅動用戶界面,處理觸控事件,因此如果在主線程中處理太多任務,那么應用就會變慢。為了解決這一問題,我們盡量在后臺處理對計算資源要求較高的任務,包括所有網絡活動、JSON分析、NSManagedObject對象創建以及存盤等。
可以再舉另一個例子。我們使用Core Text顯示字符串,但排版計算很快成為一個瓶頸。在新版iOS應用中,當我們下載新內容時,我們以異步方式計算字符串大小,緩存在CTFramesetters中,當需要在UITableView中顯示時再利用這些計算結果。
在iOS中啟動Facebook應用時,你會想看見動態匯總,而不是正在加載的下拉列表。因此,為了提供最好的體驗,我們在應用啟動時立即顯示此前緩存的內容。不過這帶來了新問題:如果你的動態匯總中內容太多,那么UITableView將調用一個委托函數tableView:heightForRowAtIndexPath:,對每條內容進行處理,以計算滾動條長度。這將導致應用需要從磁盤中加載所有內容,對整個內容排版進行計算,隨后返回所有內容的高度總和。這意味著,當動態匯總中內容過多時,啟動速度會變得更慢。
解決這一問題的方法分為兩部分。首先,當我們初始化異步排版計算時,我們在Core Data中存儲了內容的高度。通過這樣做,我們避免了在tableView:heightForRowAtIndexPath:函數中計算排版信息。其次,我們將“內容”的模式對象進行分解,在應用啟動時只會從磁盤讀取內容的高度信息,隨后才讀取其他信息。而其他的排版計算均通過異步方式來完成。
通過以上這些方式,我們在屏幕滾動時實現了更高的幀率,并使應用保持響應。
新的基礎:Messenger及其他
開發人員總是避不開一些限制,一些是技術上的,一些是設計上的,一些則是由產品需求引起的。當我們重新開發iOS應用時,一款新的原生應用Facebook Messenger正越來越流行。為此,我們需要完全集成Messenger的底層架構和用戶界面,并充分利用Messenger團隊此前已經過充分測試的代碼。當點擊iOS應用中“Messages”圖標時,運行的代碼將與Facebook Messenger應用完全一致。
為了實現這一目標,我們按模塊來搭建系統。當你在左側導航菜單中點擊書簽時,模塊提供的視覺效果將得以顯示。動態匯總、Messages、Friends,這些都是模塊。模塊也會說明相互之間的依賴關系。例如,我們使用MQTT去更新通知、消息和書簽。在應用啟動時,應用會遍歷依賴關系圖,確保在通知功能啟動前先啟動MQTT服務。在增加新功能時,模塊系統也將確保應用在正確時間、正確位置啟動。
盡管模塊系統部分解決了問題,但Messenger也不可能簡單地以新核心取代當前代碼。新版iOS應用中的認證系統以及Messenger應用的執行方式共享了同一界面的對象。用Objective-C的語言來說,就是“遵循了同樣的協議”。通過與Messenger團隊的合作,我們開發了依賴注入系統,向Messenger代碼提供了用于實時驗證的對象。當作為一款獨立應用時,Messenger代碼以自己的方式處理這些對象。當作為Facebook應用的一個模塊時,將采取不同的處理方式。在代碼中加入這些對象是一個聰明的做法。
針對未來的計劃
目前,動態匯總中的內容都有頁面頭,其中包括內容預覽圖、時間戳、消息、照片、視頻,以及“贊”和“評論”按鈕。這通過HTML5很容易實現,并且可以快速更新設計,例如用戶何時更新了動態匯總,使照片尺寸更大等。不過,動態匯總也在持續發展,當我們增加新功能時,采用Objective-C的方法將帶來新的挑戰。
為了解決這一問題,我們采用不同的方式去增加新功能,同時不必升級整個應用,這就是“回退渲染器”。當動態匯總團隊設計了一種新的內容形式時,iOS應用將下載到一些無法識別的內容。當我們檢測到這種內容時,我們將使用回退渲染器,以應用可識別的格式顯示新內容中的相關信息。與此同時,我們開發了新的定制渲染器,在下一次應用升級時發布。對于應用中可能經常更新的部分,我們仍將繼續使用HTML5代碼,這樣我們可以在服務器端推送升級,而用戶不必下載新版本應用。
你口袋中最好的Facebook體驗
開發原生iOS應用使我們有能力保證應用的速度、可靠性和功能。無論使用時間是30秒,還是乘火車旅行,我們都希望你能有快速而滿意的體驗。我們認為,移動是Facebook最好的平臺,并希望在任何時間任何地點通過這一平臺提供最好的Facebook體驗。新版iOS應用只是我們其中一步。