天天看點

[譯] Facebook:我們是如何建構第一個跨平台的 React Native APP

早些時候,我們介紹過​​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就可以了。

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

首先實作廣告工具的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.

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

開發Android版本

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

幸運的是,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版本。​

繼續閱讀