經過近兩個月的準備,攜程無線平台研發團隊正式將內部的React Native開發框架 - CRN 實現開源。CRN對原生的React Native框架進行了大量架構簡化、性能和穩定性調優的工作,能大幅降低RN技術的應用成本。

背景

攜程從2016年年中正式引入React Native,至今已將近3年,現在逐步穩定,並成為內部首選的跨平台開發方案。

先簡單回顧下ReactNative在攜程的發展軌跡

  • 2016年,RN 0.30.0版本,試驗期
    • 少數對性能和動態性都有要求的業務模塊使用,其它大多選擇流量小的業務流程做嘗試;
    • 完成了打包Bundle拆分、框架預載入等核心性能瓶頸的優化;
    • 配套文檔、發布系統建設;
  • 2017年,RN 0.41.0版本,大面積使用期
    • 攜程旅行App各業務線都有接入使用,大量原先使用傳統Hybrid技術開發的業務,切換到CRN;
    • 為解決複雜業務的首屏渲染性能問題開發LazyRequire方案;
    • 配套的發布監控、異常監控、性能報表系統建設;
  • 2018年,RN 0.51.0版本,爆發期
    • 業務大規模接入,大多是主流程、全流程使用,現在大家使用的攜程旅行App中有超過一半的頁面都是RN開發的;
    • 集團內其他核心App (智行、Trip.com、攜程商旅等) 全部接入使用;
    • Android平台的穩定性大幅提升;
  • 2019年,RN 0.59.0版本,穩定期
    • 剛升級完成,本次開源也是基於該版本;

為什麼開源

  • 分享我們對RN框架的性能優化方案
  • 期待業內使用RN技術的同行通過開源社區與我們進行更深入的交流

開源內容

CRN作為一個整體解決方案,涵蓋了從開發框架、工具、文檔、測試、發布到運維全研發生命周期的支持,與大量內部系統打通,並定製了適合攜程研發組織結構的開發流程。

本次開源基於ReactNative 0.59.0, react 16.8.3版本, 開源的主要是性能優化部分, 也是規模化使用RN進行業務開發必須要做的優化。

  • CLI
    • 工程創建、調試和運行
    • 打包時拆分框架和業務代碼
    • 打包時生成一套打包產物 (可同時運行在iOS和Android平台)
    • 打包時支持增量編譯 (同一JS模塊多次編譯模塊ID不變,便於差分更新)
    • LazyRequire, 按需載入
  • Runtime
    • 打包出的框架代碼後台預載入
    • 業務代碼緩存策略 (提升業務首屏二次打開速度)
    • 穩定性增強
    • 首屏渲染性能統計

適用場景

  • 純RN App
    • 因為啟動就是RN業務,首頁無法享受框架預載入帶來的載入提速
    • 如果有多個業務包,CLI的拆包可以減小包大小
    • 使用CRN開源的Runtime(iOS/Android native代碼)可以增強RN的穩定性
  • 混合型 App
    • CRN的優化是針對該場景,所有功能點都適合

改造優化

舉例介紹其中兩個重要的優化場景:

首屏載入性能

  • 運行Demo工程中的Tester模塊 (為RN官方提供的測試模塊)
  • 在iPhone 7Plus、iPhone 6、Samsung S6 Edge+ 三款機型上測試
  • 分別採用CRN和標準RN兩種模式載入

統計頁面的首屏載入時間,對比圖如下:

可見CRN優化後的頁面首屏載入時間與優化前RN官方的方式相比在iOS上減少了50%左右,Android上減少了60%左右,優化效果明顯。

框架和業務代碼拆分

以RNDemo工程為例(僅包含一個類似於HelloWorld的頁面)

  • 官方命令打包出的main.js 624KB
  • CRN打包業務代碼js-modules目錄2KB,common_ios.js 615KB
  • 如果大量業務模塊使用RN開發,CRN打包方案,只有一份框架代碼common_ios.js, 可以大幅減小安裝包體積。

CRN工程介紹

CRN的開源項目地址:github.com/ctripcorp/cr

有分析過react-native倉庫源碼的同學應該會對項目工程結構感到很困惑,因為整個項目很龐大,涉及到Native Runtime、Component、Tool、Tester代碼,還有不少的第三方依賴和組件管理工具的配置,結構也不是太清晰,所以官方現在進行了Lean Core的項目,目的就是對工程結構進行梳理,將非核心功能都移動到獨立倉庫。

React Native涉及的技術棧比較廣,包括iOS/Android native開發、React組件開發、nodejs開發、還有大量的C++庫,能同時能掌握這麼多技術棧的工程師不多,CRN對RN的runtime,打包腳本都做了調整,為了能儘可能降低理解和接入成本,我們對CRN的開源工程做了大量簡化,提供開源代碼的同時,也將對應的CLI發布到了npm上,方便大家使用。

開源代碼主要包括兩部分

  • Runtime
    • 分為iOS和Android兩個目錄,內部包含CRN修改的RN代碼
    • 默認帶了CRNDemo工程,IDE中可以直接運行
  • CLI
    • 和ReactNative的開源工程類似,開源的代碼直接使用起來比較繁瑣,所以提供了類似於react-native的CLI以簡化使用
    • CLI的使用參考GitHub中文檔

如何上手

為了方便接入,首先安裝crn-cli, 執行 npm install -g crn-cli 即可

現有App如何接入?

  • Native Runtime接入
    • 將iOS/Android目錄下的Runtime代碼替換RN官方代碼,具體參考項目README文檔
    • 啟動邏輯中添加webapp目錄代碼物拷貝到工作目錄,可參考CRNDemo工程源碼
    • 啟動時調用框架預載入代碼

//iOS - CRNBridgeManager.h
- (void)prepareBridgeIfNeed;
//Android - CRNInstanceManager.java
public static void prepareReactInstanceIfNeed()

  • JS代碼接入
    • 在現有JS入口文件如index.js中添加一行模塊導出代碼,示例如下:

AppRegistry.registerComponent(appName, () => App);
module.exports = App; //添加一行模塊導出代碼即可

    • 使用crn-cli pack命令打包,並將打包產物拷貝到Native工程的webapp目錄

全新App如何接入?

  • crn-cli init <project-name> 初始化工程,裡面包含iOS、Android、JS代碼
  • crn-cli run-ios , crn-cli run-android 運行RN工程,進行開發調試
  • crn-cli pack 打包,並將打包產物拷貝到Native工程的webapp目錄

總結

CRN是經過攜程大規模生產驗證的RN開發框架,我們通過對原生RN框架的改造,實現了更低的RN技術應用成本,同時解決了眾多面對線上場景的工程技術問題。

未來我們將盡量保持開源版本與內部版本的一致,並開源更多工程和效率相關的模塊與組件,期待同行在GitHub上向我們提出關於RN技術的想法和反饋意見。

【作者簡介】趙辛貴,攜程無線平台研發部開發總監。2013年加入攜程,主要負責App基礎框架研發相關工作,曾參與Native、Hybrid和React Native框架設計、工程模塊化、Android插件化等項目。目前重點關注React Native技術在公司的推廣和研發支持、無線框架和工程架構升級。

更多攜程技術人一手乾貨,歡迎搜索關注「攜程技術中心」微信公眾號~


推薦閱讀:
相关文章