原本準備寫一篇完整的文章介紹下我司的 React Native 總體方案的實踐,可是下筆以後發現話題實在太多太長,很難寫成一篇觀點集中的文章,因此計劃分幾篇文章來介紹,但願對正在或者準備在 RN 上搞事情的同窗有所啓發,另一定要根據本身的業務場景來考慮問題,切勿人云亦云,不知因此。因此本文除了介紹咱們最終是怎樣作的以外,我會着重強調「爲何這樣作」。javascript
本文主要講的是 RN 版本依賴和熱更新相關的話題,這是咱們團隊的 RN 方案和業界流行的方案差別最大的地方,也是咱們耗費心力最多的部分。本文會先講一下方案的主要思想,而後介紹下場景和原因,最後詳解一些細節的實現。前端
下文以 SRN 表明咱們團隊的 React Native 方案(souche react native)。java
首先介紹核心思想,在咱們團隊內部,最開始對 React Native 的版本依賴就達成這樣一個共識:react
其實咱們整個方案都是圍繞這兩個重點來實現的,不少同窗看到這兩個核心點可能會很是困惑,可能就此結束閱讀此文,可是我是但願你們可以繼續看下去,看一下爲何咱們要這樣作再作決定。npm
要討論這個話題,其實首先須要討論一個終極問題:爲何要引入 RN?不一樣的團隊可能會給出不一樣的答案,這都無可厚非,畢竟每一個團隊的問題和場景都不一樣,天然引入一個新技術的理由也不一樣,惟一最差的理由可能就是「沒有理由」。json
對於咱們團隊來講,引入 RN 並非由於它的代碼能夠熱更新這個特性,H5代碼自帶遠程屬性,爲何不用H5而是要用RN?咱們的場景,偏B端,重交互而輕營銷,產品關注的主要是穩定性,而不是隨時變化的能力。對於須要靈活變化的場景,用H5徹底能夠知足需求,交互和體驗/開發效率都沒有太大問題。因此我後來一直跟你們強調,RN 毫不是用來替換 H5 的。那爲何要引入 RN 呢,其實在咱們正式引入 RN 以前,咱們已經在 RN 上積累了半年多,甚至組件庫都作出來了,可是歷來沒有在業務中嘗試。後來,有一個契機,公司在C輪以後走向了團隊規模極速擴大的道路,以前咱們公司不少B端產品都是重客戶端的,這時候團隊的瓶頸開始凸顯,業務的客戶端開發成本很高,Native的一些缺點開始暴露,例如 開發不夠靈活/跨端技術棧發展不統一/人力成本double(這是最突出的問題),對於須要快速試錯快速迭代的公司階段來講,RN 的優點凸顯出來了,而這,就是咱們引入 RN 的最重要的緣由。微信
想清楚了爲何要引入 RN 以後,應該如何使用 RN 也就很清楚了,咱們並不特別關注 RN 的熱更新能力,而最關注的主要是兩點:app
1、如何將 RN 的開發工程化,無論是客戶端開發仍是前端開發,均可以用這套方案快速開發普通的業務。框架
2、穩健性。包含多個方面,底層的穩定,代碼健壯性,版本依賴管理。maven
第一點,咱們以後再講,這是咱們整套體系中的一部分,作了不少事情來保證業務能夠被快速生產,包括腳手架和開發框架/組件庫等。而第二點,就是文章開頭咱們提到的核心思想。
我先解釋下,什麼叫作強依賴。一句話表達就是:特定版本的app中某個 RN 業務的bundle的版本也會被鎖定在某個版本,區別於覆蓋式熱更新和H5的實時訪問機制。
爲何須要這麼作?有如下幾個因素考慮:
不知道你們在使用覆蓋式熱更新的時候有沒有遇到這些問題,但願能有所啓發。
強依賴是個好東西,可是熱更新也是個好東西,咱們不能捨本逐末,咱們一直在弱化熱更新的優點,可是不可否認它在某些場景下的必要性,例如緊急修復線上bug,例如一些偏營銷的業務場景,也會經過熱更新帶來快速發佈的能力。
可是,咱們在熱更新和強依賴之間作出了一個平衡,將兩者結合在一塊兒,業務方能夠將某個版本的app依賴的某個RN業務鎖定在某個版本,可是這個版本同時也具有熱更新能力,可能不少同窗已經猜到了,咱們是用兩個版本號來維護這個邏輯的,準確來講並非兩個版本號,而是一個業界統一的版本格式:語義化版本控制規範(SemVer)。
格式如 ${major}.${feature}.${patch},遵循 semver 規範的版本號
選擇須要遞增的版本號
major: 主版本號,用於斷代更新或大版本發佈
feature: 特性版本號,用於向下兼容的特性新增
patch: 修訂版本號,用於 bug 修復
遞增位的右側位須要清零,如 1.1.2 => 1.2.0複製代碼
接下來咱們就講講這裏的依賴邏輯。
接着上面語義化版本號來說咱們的具體實現,能夠發現咱們須要版本鎖定和熱更新的需求,其實和SemVer的訴求徹底一致,天然而然的,咱們用 ${feature} 來鎖定版本,用 ${patch} 來熱更新,從語義上來講,鎖定版本後須要更新功能須要升級 ${feature} 版本,這就是一個 feature,須要熱更新就是修復問題,升級 ${patch} ,這就是一個 hotfix(or patch)。
最終,其實就是咱們的app在用戶手機上運行時,會發起一個熱更新的請求,而這個熱更新的具體邏輯只會判斷「相同 ${feature} 下的最新的 ${patch} 版本號」,本文整篇的精華就是這句話,你們細細體會下。
具體到 SRN 中,其實這個邏輯不是放在客戶端,也不是放在RN代碼中。而是放在一個專門維護版本依賴關係的Node服務中,將整個過程解耦,這樣依賴邏輯能夠隨時統一更換。
每一個RN業務發佈的時候都會講包先上傳到 CDN,而後將此次發佈的信息記錄到這個 Node 服務中(若是不當心發錯了版本,在Node服務中操做一下就能夠刪掉一次發佈),而後每一個用戶app啓動的時候,會把用戶本地的全部RN業務包和他們的版本發送給Node服務,Node服務會在服務端判斷 咱們剛纔提到的這個邏輯,返回「相同 ${feature} 下的最新的 ${patch} 版本號」,而後客戶端就會啓動熱更新邏輯去更新Node服務返回的最新版本的bundle。
這裏還有一點須要提到,其實咱們對 ${major}.${feature}.${patch} 還作了擴展,以便支持測試/開發/預發 環境上的版本,例如測試環境上的版本號會是這樣:0.1.2-beta.8,也就是發佈測試版本不會增長 ${patch} 版本,而是會在擴展字段上增長 ${beta} 版本,對於擴展字段,由於是開發環境,處理規則是和 ${patch} 版本同樣,直接熱更新,因此除了線上環境,全部其餘環境更改代碼都不須要從新定義依賴。
另一個問題就是這麼複雜的版本規則,如何友好的暴露給開發者?其實對於開發者來講,根本不須要本身維護版本號,也不須要知道這個規則,在業務發佈前,腳手架會給選擇,「環境:測試、預發、線上」,「發佈類型:功能迭代、bug修復」,這些都是交互式命令,選擇對應命令後,會自動升級當前業務的版本號,自動發佈和打tag,無需開發手動維護。
用邏輯圖表示:
關於版本依賴鎖定和熱更新其實到這裏基本結束了的,可是仔細深刻思考的同窗應該發現好像少了點什麼,的確,有這些還不夠,你的整個流程還跑不起來,少了最關鍵的一步:依賴聲明和本地集成。
特別是第一次發版的時候,客戶端如何知道當前版本的app依賴了哪些業務和鎖定這個業務的哪一個 ${feature} 版本呢?
在開始的時候,咱們的方案是在app的工程裏維護一個package.json 同樣的文件,內部聲明好 dependence,和 npm 包的 package.json 格式相似。而後在jenkins或者ide裏打包app的時候,會執行一段腳本,這個腳本會將這個package.json的內容上傳到剛纔提到的 Node 服務中,服務會走一個跟線上熱更新一樣的邏輯,將當前鎖定的${feature}版本的最新${patch}版本返回,而後這個腳本會去下載這個最新的RN bundle,將其直接集成到工程代碼中,而且更新 package.json 內的依賴聲明。
當發佈了一個線上bundle的時候,若是選擇了「功能迭代」,會自動給業務的 ${feature} 加一,這時候須要發佈新版本的客戶端,就要手動去改一下 package.json 中的這個 bundle 依賴的版本號,例如業務從 1.2.3 到 1.3.0,就把package.json中的版本號改成 1.3.0 ,若是後面你發現有bug又發佈了一次,不須要再改 1.3.1 了,打包的時候運行的腳本會自動幫你改掉。也就是每次發版後,這個版的app內都會默認跟一個業務的最新版的bundle。
這樣作看起來挺完美的,可是後來咱們發現仍是有很多問題的,例如,咱們的腳手架沒有把這個版本號的規則太多的暴露給開發者,可是開發者卻須要在每次發版前維護客戶端中的這個依賴,咱們的app以及業務發版都很頻繁,形成整個流程不暢。另外打包的腳本穩定性和運行性能都會影響打包的過程,這個侵入對客戶端和測試同窗體驗很差。
如今,咱們立刻就會上一個新的方案,原理是將全部RN的包從概念上包裝成 Native的包,例如iOS的pod包,Android的maven包。每次發佈的時候,除了以前的流程,如今最後一步,咱們會把js bundle分別包裝成一個 iOS 的 pod包,Android 的 maven 包。而後客戶端直接將 RN 的業務當作一個正常的Native業務來使用。
這樣,去掉了兩個動做:app打包時不須要執行集成腳本了,對 app 打包流程沒有任何侵入;另外,不須要在客戶端聲明額外的依賴了,客戶端只須要用傳統的方式,在 podfile 或者 gradle 裏聲明依賴就能夠,pod包和maven包的版本和RN業務的版本徹底一致,規則也一致。
固然,這裏省略了不少細節,若是你們有須要詳細瞭解的,能夠私下聯繫我。
由於有版本依賴鎖定,最近咱們的 SRN 整個升級到 0.43 以及 集成 bundle 拆分的功能 還有整個集成過程的完全改變,都很是輕鬆,升級過程徹底無痛,若是你們有遇到一樣的困惑,能夠參考一下。後續其實咱們也打算在某些偏營銷的場景中,能夠不經過發版集成直接在一個app中訪問一個RN業務,其實在現有的機制上作一點小改動便可,仍是那句話,看場景,不要完全否認某些方案,可能只是你們遇到的場景不一樣,而技術的價值正式解決業務場景中的問題,而不是爲了技術而技術。
有問題歡迎加我微信:mier963 諮詢,感謝閱讀。