Dropbox 的開發人員最近分享了他們在移動 App 開發方面的經驗。App 如何才能做到同時支援 iOS 和 Android 兩個平臺而又不需要在每個平臺上對相同的功能重複編碼。下面就讓我們詳細瞭解一下他們為什麼這麼做,從中得到什麼好處以及在這個過程中探索出哪些關鍵經驗。
幾個月前,Dropbox 的開發人員 Stephen Poletto 和 Sean Beausoleil 在給 Facebook 的開發人員做講座時提到,iOS 和 Android 平臺程式碼庫的不一致會帶來一系列問題:
- 開發和維護成本成倍增加。
- 開發團隊需要多次修復同樣的缺陷。
- 針對某個平臺報告的缺陷可能會被另一個平臺忽視掉。
- 不同平臺的 App 行為可能會有預料之外的細微差異。
- 效能優化成本高昂並且與平臺相關。
Dropbox 賴以克服上述這些問題的策略基礎就是為所有 UI 無關的程式碼建立一個共享的跨平臺 C++ 庫,例如資料和網路部分的邏輯。UI 部分還是使用原生程式碼編寫,以便儘可能地利用平臺對動畫特效和裝置感測器等的支援,並且確保充分的響應速度。
與更傾向用 HTML 5 或 JavaScript 等較抽象語言的自頂向下的方法相對應,Poletto 和 Beausoleil 將這種方式描述為自底向上的方法。據兩位開發人員介紹,這些方法通常難以達到預期的效能要求。
另外一方面,iOS 平臺能夠很好的支援 C++ 程式碼,而且這些程式碼也可以很方便的與 Objective C++程式碼結合。並且,儘管不像 iOS App 那樣方便,Android App 也可以通過 Android 原生開發元件(NDK)使用 C++ 程式碼。
在 UIKonf 2014大會上,Mailbox app 的開發者 Steven Kabbes 為聽眾解釋了 Dropbox 開發者如何通過 gyp 來處理 NDK 開發的複雜性,Google 的元構建(meta-build)系統可以用一個JSON 描述檔案生成Xcode 專案,Android 和 Unix 下的 makefile 檔案以及 Visual Studio 專案。Steven 還在 GitHub 上釋出了一個專案來展示 Dropbox 中使用到的一些跨平臺技術。
C++層的設計
Dropbox 的跨平臺 C++ 層架構比較簡潔,包括:
- 一個 SQLite 資料庫,扮演著“真相來源”的角色。
- 一個獨立執行的同步服務執行緒,以保持 Dropbox 伺服器和本地 SQLite 資料庫的同步。
- 一個操作佇列,維護所有尚未執行的使用者操作。
- 一個操作執行緒,負責從操作佇列中提取使用者操作,並在 Dropbox 伺服器上執行這些操作。
Dropbox 跨平臺 C++ 層的基本理念是在它和原生程式碼之間劃分出明確的邊界。這意味著 C++ 層與 UI 層之間沒有任何資料共享,而且物件的來回複製也要穿過層與層之間的邊界。這種策略的優點在於當涉及到併發時,兩個層次可以被認為是完全獨立的,因此它們不需要任何跨層的鎖定,並且可以在無需考慮另外一方的情況下處理併發。
Dropbox C++ 層的主要元件是一個由 SQLite 驅動的查詢和持久化框架,讓 Dropbox 開發者可以避免使用 iOS 平臺上的 Core Data 框架。Kabbes 解釋說,Core Data 是一個快速而強大的框架,這個決定並不是由於 Core Data 框架本身的問題,完全是為了滿足同時支援 Android、iOS、Mac 平臺的需求,將來還需要支援 Windows 平臺。這個元件並非為了完全替代 Core Data 框架,而只是提供持久化和查詢的功能,加上用以保證 UI 反應速度的一個元件,即與 NSManagedObjectContextObjectsDidChangeNotification 功能類似的一個 C++ 通知機制。Kabbes 認為這是一個非常關鍵的元件。通過這一機制,只需要傳輸增量的變化。關於持久化元件的更多細節資訊可以閱讀 Kabbes 在 GitHub 上的筆記和Ole Begemann 發表的博文。
設計跨平臺 C++ 層時,面臨的一個難題是權衡什麼情況下需要從頭開始重新實現 OS 本身已經提供了的功能,什麼情況下僅需編寫包裝器(wrapper)封裝這個功能。正如 Poletto 所說,你不可能用 C++ 重新實現整個平臺。因此,對於網路訪問或 SSL 證照驗證等基礎功能,會通過封裝的方式從 C++ 層回撥到原生平臺。Ole Begemann 列舉了幾個例子說明哪些功能不適於重新實現,例如,使用 NSURLSession 進行的後臺下載,App 的後臺行為,以及 iCloud 訪問等。其他一些情況下,則可以重寫那些由平臺相關的 API 所提供的功能,例如 NSUserDefaults 已經被 LevelDB 替換成 Dropbox 的程式碼。
據 Poletto 介紹,在 iOS 和 Android 平臺之間共享同一個程式碼庫能夠帶來一系列的好處。首先,幾乎可以肯定,iOS 和 Android 團隊之間會有更加緊密的協作。其次,開發團隊能夠更早地捕捉到缺陷,並且可以在兩個平臺上同時修復這些缺陷。再次,效能調優可以同時優化兩個平臺。最後,Dropbox 可以利用 Android 的 beta 測試程式來測試“iOS 程式碼”,這樣就可以立即修復問題而不需要等待 App Store 的審查過程。