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版本。
相關文章
- Facebook 是如何構建第一個跨平臺的 React Native APPReact NativeAPP
- Facebook 是如何做第一個跨平臺的 React Native APPReact NativeAPP
- 我的第一個React Native AppReact NativeAPP
- 看Facebook是如何優化React Native效能優化React Native
- React Native 學習指南(一) - 構建第一個應用React Native
- 跨平臺開發之React Native初體驗React Native
- 從 React Native 到 Flutter,移動跨平臺方案的真相React NativeFlutter
- 使用Electron構建跨平臺的桌面應用
- 從零到一:用ReactNative開發的第一個跨平臺appReactAPP
- 移動跨平臺方案對比:WEEX、React Native、Flutter和PWAReact NativeFlutter
- 《React Native跨平臺移動應用開發》讀後鬼扯React Native
- cordova + vue cli構建跨平臺應用Vue
- 使用React、Electron、Dva、Webpack、Node.js、Websocket快速構建跨平臺應用ReactWebNode.js
- 我們是如何使用 Electron 構建 Linux 桌面應用程式的Linux
- 【全棧React】第3天: 我們的第一個元件全棧React元件
- 跨平臺專案GSYGithubApp系列三大開源版本推薦(Flutter 、React Native 、Weex)GithubAPPFlutterReact Native
- React Native Linking跨app的通訊方法React NativeAPP
- 思否開源專案推介丨Remax:使用 React 構建跨平臺小程式REMReact
- 淺談移動應用的跨平臺開發工具(Xamarin和React Native)React Native
- [譯] Airbnb 在 React Native 上下的賭注(三):建立一個跨平臺的移動端團隊AIReact Native
- 跨平臺通用賬號系統如何選擇?Facebook 成出海 App 強力後援APP
- 前端之React實戰:建立跨平臺的專案架構前端React架構
- Java是如何實現跨平臺的?原理是什麼?Java
- 《PhoneGap精粹:構建跨平臺的移動App》——1.4節為容器而設計APP
- React Native區分安卓/iOS平臺React Native安卓iOS
- 跨平臺專案GSYGithubApp系列三大開源版本推薦(Flutter 、React Native 、Weex、Kotlin)GithubAPPFlutterReact NativeKotlin
- 讓我們構建一個Swift.ArraySwift
- 我的第一個 APPAPP
- 跨平臺開發的救星-讓我們來了解一下flutterFlutter
- Electron構建跨平臺應用Mac/Windows/LinuxMacWindowsLinux
- 我是如何構建一個持續發展的專案
- React-Native修改安卓平臺的包名React安卓
- 我們要的是一個簡單的react-router路由React路由
- Java如何實現跨平臺?原理是怎樣的?Java
- Google Inbox 是如何跨平臺重用程式碼的?Go
- 我們評測了5個主流跨端框架,這是它們的區別跨端框架
- 設計和而不同的跨平臺AppAPP
- 在React Native中構建啟動屏React Native