Facebook 是如何構建第一個跨平臺的 React Native APP

ljinkai發表於2015-10-02

今年早些時候,我們介紹過iOS版的React Native. React Native帶來的是用web方式的React – 自宣告式的UI元件和快速的開發迭代來完成手機平臺的功能,然後為了保持速度、保真性、並達到原生的體驗。今天我們很高興釋出React Native的Anroid版本.

在Facebook我們已經應用React Native在釋出的產品有超過一年的時間了。幾乎是整整一年之前,我們的團隊開始規劃開發廣告管理APP。 我們的部門是建立一個新的APP來讓數百萬的Facebook廣告主來管理他們的賬號並能建立新的廣告。在完成的時候,這不僅僅是FB的第一個全 React Native APP而且是第一個跨平臺的APP.在這篇文章裡,我們希望能和你分享我們是如何構建這個APP,React Native是如何讓我們更快的,還有這個過程中我們的經驗。

選擇React Native

不久前,React Native還是一項新的技術,還沒有被一款正式的產品應用過。並且開發這樣一個新的APP會有很大的挑戰,它超過了潛在的好處。

首先,我們初始的團隊裡有三個產品工程師已經對React很熟悉。另外,這個APP需要處理大量複雜的商業邏輯和精確的處理不同的廣告格式、時區、 日期格式、貨幣、匯率等等諸如此類。而大部分已經用JavaScript來實現了。全部用Objective-C編碼並稍後用java實現Android 版本的想法也並沒有被贊成,而且也並不高效。第三,用React Native將會很容易來實現大部分的UI,可以實現帶資料的列表、表格、圖表。產品工程師可以很快的實現這些效果,用React就可以了。

當然,一些特性的實現存在著挑戰 – 比如,圖片的編輯,用來讓廣告主縮放和剪下圖片;地圖檢視,用來讓廣告主設定地理範圍。另外一個是麵包屑導航,幫助廣告主來視覺化的知道自己的層級位置。這些都提供機會讓我們來推動這個平臺的發展。

Facebook:我們是如何構建第一個跨平臺的React Native APP
Facebook:我們是如何構建第一個跨平臺的React Native APP

首先實現廣告工具的iOS版本

我們的團隊覺得首先開發iOS版本,也是為了和React Native的iOS版本校準一致。我們從後面的幾個月時間裡從3個增加到8個工程師。新加入的成員對React並不熟悉 – 其中也並不熟悉JavsScript – 但是他們都渴望構建一個偉大的手機應用來服務廣告主,並且他們成長的非常快。

有經驗React Native的iOS工程師幫助我們實現一些他們並沒有在React Native中實現的特性,像提供訪問相簿。他們也幫助我們和其它FB已經存在的APP在使用的iOS庫做關聯,像認證、分析、崩潰報告、網路和推送提 醒。這讓我們的團隊可以關注在產品上。

除了上面提到的,我們可以使用以前就寫好的JavaScript類庫。像Relay,一個通過GraphQL來 傳遞資料到React應用的FB框架.另外的一系列庫用來處理國際化和本地化,它能很聰明的實現時區和貨幣的呼叫。這些庫的載入是在一個JSON的配置文 件裡,包括APP用到的iOS的本地關聯檔案,僅僅暴露很少的native程式碼。這讓我們的庫幾乎不需要修改就能使用。

我們遇到的最大的挑戰就是導航。為了導航廣告主的廣告和活動,我們想使用麵包屑導航條。指引廣告的建立流程,我們需要一個導向式的導航條。在最上面,非常重要的是需要使用合適的動畫和手勢操作,否則這個APP看起來還是像一個經過美化的website.

我們的解決方案是使用導航元件, 是一個用React Native來實現的可定製化的元件。本質上,它是一個追蹤一系列React元件的元件。它可以在元件之間基於按鈕點選和按下時進行動畫切換。它也具有可 插拔式的導航元件,讓我們來實現iOS風格的導航檢視,以麵包屑的方式來導航廣告和活動,指引建立流程的步驟。這個導航條元件還能獲取到動畫的進度以及根 據需要來調整動畫的頻率。這意味這所有動畫,包括檢視和導航條都可以通過JS來處理,而且測試的結果是仍然能夠達到60fps.

Facebook:我們是如何構建第一個跨平臺的React Native APP

只有一種情況下動畫才會卡頓,就是當JS執行緒被一個大的操作佔用時。當我們遇到這種情況時,基本上都是執行大量的資料獲取操作造成的。必然的,當導 航到新頁面時需要載入大量的資料。當網路足夠快是,動畫可以很容易的被執行。我們的解決方案是延遲資料的獲取直到動畫執行完畢,這時就使用到了InteractionManager元件,同樣是React Native的一部分。我們首先動畫到一個新的檢視,然後再用Relay來執行資料載入程式,這樣就能自動的讓需要的React元件實現自動渲染了。

開發Android版本

當iOS版本的廣告管理工具接近開發完成時,我們開始著手Android版本的APP.移植React Native的Android是最好的方式來完成這個工作。幸運的是,React Native團隊已經在上面做了很多的工作。自然的,我們想盡可能的複用更多的程式碼,因為大部分的檢視都很相似。當然,也有一些地方需要做Android 個性化處理來和iOS版本有所區別,比如,導航的元素或者是呼叫本地的UI元素像日期選擇、開關等等。

Facebook:我們是如何構建第一個跨平臺的React Native APP

幸運的是,React Native包的黑名單特性和React的抽象結構幫助我們最大化的重用程式碼來實現跨平臺的功能。在iOS版本里,我們打包的時候忽略所有字尾名 為.android.js的檔案。對Android的開發,忽略掉所有字尾名為.ios.js的檔案。現在我們可以實現同樣的元件來同時應用 Android和iOS,也可以個性化的編碼在不同平臺。替換掉 if/else 這種方式來判斷平臺,我們嘗試重構每個平臺的特定UI,這樣就可以有Android和iOS的不同實現。在構建Android版本的過程中,大約85%的 程式碼可以被複用。

另外一個挑戰是怎麼管理原始碼的問題。Android和iOS的程式碼庫在Facebook兩個不同倉庫。廣告管理工具的iOS原始碼在iOS倉 庫,Android版本的程式碼在Android的程式碼庫。舉例來說,像iOS版本的程式碼,我們想用一些Facebook的Android的依賴庫,這些庫 卻在Android的程式碼庫存放。另外,Android的APP所有的編譯工具,自動化,以及引入的其它外掛都在Android的倉庫。基於上 面,Android的這些app要求重構這些已經存在的iOS程式碼來抽象具體平臺的元件來呼叫各自的檔案。我們是可以直接合並兩個版本的程式碼到一起。但是 這種方式卻是我們不能接受的。

最後,我們決定指定iOS庫為事實上的原始碼庫,因為iOS版本已經相對穩定。我們設定了定時任務許多次一天來同步iOS的JavaScript到 Android的程式碼庫。我們不鼓勵在Android版本提交JavaScript程式碼,如果提交也是在iOS版本同步的提交一份。如果同步程式碼發現程式碼 有差異,會記錄一個任務用來進行後續的檢查。

我們讓iOS倉庫的JavaScropt打包成可以在Android版本上執行的程式碼。這樣我們的產品開發人員就可以接觸到儘可能多的 JavaScript程式碼而沒有原生程式碼,也可以直接在iOS倉庫直接修改和除錯兩個版本的程式碼。但是如果要構建Android的APP還是需要在 Android倉庫來執行,同樣的操作也會在iOS APP – 測試兩個平臺的不同需要大量的額外工作。為了提高JavaScript開發者的工作流程,我們同樣構建了指令碼來下載合適的來自整合伺服器的原生檔案。對於 大部分開發者來說就不需要複製一份Android的程式碼庫了 – 他們就可以在iOS程式碼庫開發完整的JavaScript程式碼,並且能比在Facebook的web流程中更快速的進行迭代。

我們學到的

React Native團隊開發的程式和我們的APP一起,並且和他們一起除錯本地化元件和API。這些元件將會為每個構建APP的人帶來幫助。儘管我們必須自己來 構建一些元件,用React Native代替純原生的方式仍然是有價值的。我們不得不需要寫這些元件,雖然在未來的一段時間裡也可能不會被其它團隊再次使用。

學到的另外一課是在分開的iOS和Android程式碼倉庫工作是一件困難的事情,儘管使用了大量的工具和自動化。在構建APP的過程 中,Facebook用過這樣的模式,我們所有構建的自動化和開發程式都建立並圍繞著它。然而,對於產品來說,用一份共享的JavaScript程式碼庫, 這種方式並不好。幸運的是,Facebook已經對所有平臺都統一了程式碼庫 – 只需要一份JavaScript的拷貝,同步那樣的方式已經成為了過去。

另外學到的是關於測試。當做了修改,每一個工程師一定要在所有平臺仔細測試,這個過程很容易出現人為的錯誤。但是開發一個跨平臺的APP而且是用一 套程式碼,這些是必須的。即便如此,由於測試不足導致的成本,遠大於用React Native開發的成本和能重用跨平臺程式碼的成本。請記住,這裡說的不僅僅是產品工程師;同樣包括React Native平臺的Objective-C和Java工程師.他們的工作不是限制在原生語言。同樣包括JavaScript – 舉例來說,元件API和部分分享部分的實現。ISO工程師一般來說不必一定要測試修改後的Android的程式碼,對應Android工程師也是一樣。這種 文化缺陷需要我們用時間和努力來消除,隨著時間的推移,我們會越來越穩定。

在每次修改整合版本的時候我們也會標記問題。這些標記的東東可以獲取iOS版本的問題,同樣的對Android也適用,我們連續的整合版本不會在 iOS修改的時候來執行Android的測試,反過來也一樣。這樣工程師就可以更多精力來解決問題,並且不用經常的來重啟APP.

隨著上面說的和做的,我們的債算還完了 – 我們可以執行Facebook的第一個完全的React Native APP在兩個平臺上,具有原生體驗,同樣的JavaeScript工程師團隊。他們當中有些還並不熟悉React, 但是他們在5個月之後就開發出了具有原生體驗的iOS版本,之後三個月,我們又釋出了Android版本。

相關文章