跨平台框架與React Native基礎
- 2020 年 9 月 16 日
- 筆記
跨平台框架
什麼是跨平台框架?
這裡的多個平台一般是指 iOS 和 Android 。
為什麼需要跨平台框架?
目前,移動開發技術主要分為原生開發和跨平台開發兩種。其中,原生應用是指在某個特定的移動平台上,使用平台所支援的開發工具和語言,直接調用系統提供的 API 所開發的應用。
其優勢體現在:
- 可以快速訪問本平台的全部功能,比如攝影機、 GPS 等;
- 原生應用的速度快、性能高,而且可以實現比較複雜的動畫和繪製效果,用戶體驗較好。
缺點也很明顯,主要體現在:
- 開發成本較高,不同的平台必須維護不同的程式碼,人力成本也會隨之增加;
- 有新的功能需要更新時,只能進行版本升級。
針對原生開發所面臨的問題,目前已經誕生了許多跨平台框架
跨平台框架都有哪些?
根據其原理,主要分為三類:
- H5 + 原生( Cordova 、 Ionic 、微信小程式);
其主要原理就是將 APP 的一部分需要動態改變的內容通過 H5 來實現,通過原生的網頁載入控制項 WebView ( Android )或 WKWebView ( iOS )來載入。
- JavaScript 開發 + 原生渲染( React Native 、 Weex 、快應用);
採用 Web 技術棧,將 DOM 映射為原生控制項樹,體驗好,接近原生。
- 自繪 UI + 原生( Flutter );
實現了一個自繪引擎,使用自身的布局、繪製系統,所以不同平台效果能高度統一。
Flutter 簡介
Flutter is Google』s portable UI toolkit for building beautiful, natively-compiled applications for mobile, web, and desktop from a single codebase.
Flutter 是Google推出的攜帶型 UI 工具包,可以跨平台的構建精美的、原生體驗的 Mobile 、 Web 、 Desktop 應用。
Flutter 的發展歷程
2017年 Google I/O 大會上, Google 首次推出了一款新的用於創建跨平台、高性能的移動應用框架 —— Flutter 。
2018年2月, Flutter 發布了第一個 Beta 版本。
2018年5月,在2018年 Google I/O 大會上, Beta3 版本發布。
2018年6月, Flutter 發布了首個預覽版本,這意味著 Flutter 進入了正式版(1.0)發布前的最後階段。
2018年12月,1.0版本發布。
哪些企業在用 Flutter ?
- 阿里巴巴(閑魚)
- 美團( B 端)
- ……
Flutter的的優點與缺點
優點:
- 性能高:由於自繪引擎是直接調用系統 API 來繪製 UI ,所以性能和原生控制項接近。
- 靈活,易維護:由於 UI 渲染不依賴原生控制項,不會受原生布局系統的限制,這樣布局系統會非常靈活;且不需要根據不同平台的控制項單獨維護一套組件庫,所以程式碼容易維護。
- 開發體驗好:由於組件庫是同一套程式碼、同一個渲染引擎,所以在不同平台,組件顯示外觀可以做到高保真和高一致性。
缺點:
- 動態性不足:為了保證 UI 繪製性能,自繪 UI 系統一般都會採用 AOT 模式編譯其發布包,所以應用發布後,不能像 Hybrid 和 React Native 那些使用 JavaScript ( JIT )作為開發語言的框架那樣動態下發程式碼。
React Native 簡介
這句話是 React Native 官網 對 React Native 的概述,簡單明了地概括了 React Native 的特點和優點。
React Native 的發展歷程
哪些企業在用 React Native ?
- 騰訊( QQ 空間、 QQ 音樂)
- 百度(手機百度)
- 京東
- ……
React Native 的優點與缺點
優點:
- 社區龐大、上手快、開發成本相對較低。
- 原生渲染,性能相比 H5 提高很多。
- 動態化較好,支援熱更新。
缺點:
- 渲染時需要 JavaScript 和原生之間通訊,某些場景下如拖動可能會因為通訊頻繁導致卡頓。
- JavaScript 為腳本語言,執行時需要 JIT ,執行效率和 AOT 程式碼仍有差距。
- 由於渲染依賴原生控制項,不同平台的控制項需要單獨維護,並且當系統更新時,社區控制項可能會滯後;除此之外,其控制項系統也會受到原生 UI 系統限制。
React Native 和 Flutter 的對比
—— | React Native | Flutter | 相同點 | 結論 |
---|---|---|---|---|
環境搭建 | npm 、 node 、 react-native-cli 等 | Flutter SDK 和 Android Studio / VSCode 上的 Dart 與 Flutter 插件 | JDK 、 Android SDK 、 Xcode 等 | 首次配置運行成功率: Flutter > React Native |
實現原理 | React Native 是一套 UI 框架,默認情況下 React Native 會在 Activity 下載入 JavaScript 文件,然後運行在 JavaScriptCore 中解析 Bundle 文件布局,最終堆疊出一系列的原生控制項進行渲染 | Flutter 中絕大部分的 Widget 都與平台無關, 開發者基於 Framework 開發 App ,而 Framework 運行在 Engine 之上,由 Engine 進行適配和跨平台支援。這個跨平台的支援過程,其實就是將 Flutter UI 中的 Widget 「數據化」,然後通過 Engine 上的 Skia 直接繪製到螢幕上 | 在 Android 和 iOS 上,默認情況下 Flutter 和 React Native 都需要一個原生平台的 Activity / ViewController 支援,且在原生層面屬於一個「單頁面應用」 | 平台關聯性: React Native > Flutter UI |
編程開發(語言) | JavaScript 是動態語言 | Dart 是偽動態語言的強類型語言 | 支援通過 var 定義變數,支援 async / await 語法糖,支援 Promise ( Future ) 等鏈式非同步處理 | 開發便捷度: JavaScript > Dart 類型安全和重構程式碼: Dart > JavaScript |
編程開發(介面開發) | 延續了 React 的開發風格,不同之處就是更換標籤名,並且樣式和屬性支援因為平台兼容做了刪減 | 一切皆為 Widget 。控制項嵌套和樣式程式碼不分離 | 平台相關性: React Native > Flutter | |
編程開發(狀態管理) | 在 Component 內初始化一個 this.state 變數,然後通過 this.state.name 訪問,內部實現受 React diff 等影響 | 繼承 StatefulWidget ,然後在 State 對象內通過變數直接訪問和 setState 觸發更新,內部實現受 isRepaintBoundary 、 markNeedsBuild 等影響 | 調用 setState 更新,且操作不是立即生效的 | |
編程開發(原生控制項) | 整個渲染過程都在原生層中完成,所以接入原生控制項並不難 | Flutter 的整體渲染脫離了原生層,直接和 GPU 交互,導致無法直接接入原生控制項 | 混合開發支援: React Native > Flutter | |
插件開發 | npm 插件。好處:可以使用豐富的 npm 插件生態,同時減少前端開發者的學習成本。壞處: npm 包依賴複雜。每個項目都有一個 node_modules ,佔用空間(現在, yarn pnp 提供了一種更加高效的模組查找機制,消除了項目中的 node_modules ,所有的依賴包都在一個公共目錄裡面) | pub 插件。 packages get 文件一般保存在電腦的統一位置,多個項目都引用著同一份插件 | 支援插件開發 | 體驗: Flutter > React Native |
編譯產物 | 編譯後的文件主要是 bundle 文件,在 Android 中是 index.android.bunlde 文件,而在 iOS 下是 main.jsbundle | 在 Android 主要是: isolate_snapshot_instr (應用程式指令段)、 isolate_snapshot_data (應用程式數據段)、 vm_snapshot_data (虛擬機數據段)、 vm_snapshot_instr (虛擬機指令段)等產物。在 iOS 主要是 App.framework ,其內部也包含了 kDartVmSnapshotData、kDartVmSnapshotInstructions、kDartIsolateSnapshotData、kDartIsolateSnapshotInstructions 四個部分 | ||
性能 | Dart 支援的 isolate ,屬於完完全全的非同步執行緒處理,可以通過 Port 快捷地進行非同步交互,這大大拓展了 Flutter 在 Dart 層面的性能優勢。 | JavaScript 和 Dart 都是單執行緒應用,利用了協程的概念實現非同步效果 | 理論性能: Flutter > React Native | |
穩定性 | Github 上 open issue 只有700多(2020.06),整體上穩定性已經達到生產環境的要求,但由於對原生組件的依賴,隨著 Android、iOS 的系統迭代,未來仍需要持續的完善穩定性和兼容性 | Github 上 open issue 達到7000+(2020.06),在穩定性方面還有很長的路要走 | 穩定性: React Native > Flutter | |
發展未來 | 在0.59版本開始支援 React Hook 等特性,並將原本平台的特性控制項從 React Native 內部剝離到社區,這樣控制項的單獨升級維護可以更加便捷,同時讓 React Native 與 React 之間的界限越發模糊。但是由於平台關聯性太強,這些年發展較為緩慢 | Flutter UI 的平台無關性,讓 Flutter 在跨平台的拓展上更為迅速 |
如何選擇 React Native 或 Flutter
選擇 React Native,如果你希望
- 從前端工程師或 Web 開發者的視角接觸跨平台開發
- 擁有完善的工具鏈和成熟的生態系統
- 縮短產品的發布周期
選擇 Flutter,如果你希望
- 從原生開發者的視角接觸跨平台開發
- 關注產品性能和開發體驗(無需處理平台差異)
React Native 工作原理
使用 React Native 開發應用,我們通過 React 來構建應用。用 React 實現的組件會被 React 框架組織成「虛擬 DOM 」的形式,然後將「虛擬 DOM 」的渲染和交互映射到原生的視圖上面。
React 執行渲染(組件的裝載和卸載、樣式變化)操作後, JavaScript 會通知到 Native 端進行原生視圖的渲染,原生視圖的用戶交互事件觸發後,會通知 JavaScript 端聲明的回調。
React Native 在與原生框架通訊中,採用了 JavaScriptCore 作為 JavaScript Virtual Machine ( JS VM ),中間通過 JSON 文件與 Bridge 進行通訊。若使用 Chrome 瀏覽器進行調試,那麼所有的 JavaScript 程式碼都將運行在 Chrome 的 V8 引擎中,與原生程式碼通過 WebSocket 進行通訊。
一個 JS VM 實例代表一個執行 JavaScript 的自包含( self-contained )的環境。你可以用這個類做兩件事情: ① JavaScript 的並發執行; ② 橋接 JavaScript 和 Objective-C 或 Swift 的對象的記憶體管理。
JavaScript 程式碼並不是被編譯成 Native 程式碼,而是在各個平台的 JS VM 中被執行的。在 iOS 中, JS VM 是 iOS 系統提供的 JavaScriptCore ;而在 Android 中,是 React Native 這個框架提供的,打包進 APK 中的的某個版本的 JavaScriptCore (或者是 Facebook 的 Hermes 引擎)。
JavaScriptCore 主要功能是解析執行 JavaScript 腳本。它支援在原生環境( Objective-C 、 Swift 、 C )中執行 JavaScript 程式碼,同時支援把原生對象注入到 JavaScript 環境中使用,結合這兩點 JavaScriptCore 就具備 JavaScript & Native 交互的能力。 React Native 正是利用它的這一特性,在 JavaScriptCore 的基礎上構建一座橋樑( Bridge ),使得 Native 與 JavaScript 可以高效且便捷地互相調用,這便是 React Native 框架的核心。
React Native 部署調試
項目運行
iOS 平台:
- 使用 Xcode 打開 ios/.xcodeproj ,選擇模擬器後點擊運行按鈕
react-native run-ios --simulator "iPhone 8"
xcrun simctl list devices
可以獲取到 Xcode 下所有可用的設備列表
Android 平台:
執行react-native start
,打開 Android Studio
- 選擇 Configure -> AVD Manager , 點擊運行按鈕
- 打開項目, 點擊運行按鈕
開發調試
- 開發者菜單( iOS : Command + D, Android : Command + M)
- Chrome + React Developer Tools
React Developer Tools :
安裝:npm install -g react-devtools
運行:react-devtools
- React Native Debugger
安裝:
brew update && brew cask install react-native-debugger
- 真機調試
以 Android 為例:
- 開啟 USB 調試
- 使用
adb devices
命令可以檢查設備是否正確連接到 ADB ( Android Debug Bridge ),右邊那列看到 device 說明你的設備已經被正確連接了。
注意,你每次只應當連接一個設備。如果你連接了多個設備(包含模擬器在內),後續的一些操作可能會失敗。