移動跨平臺開發深度解析

注:本文爲轉載文章,部份內容參考移動端跨平臺開發的深度解析,並作了精簡和加工。前端

概述

移動跨平臺開發一直是移動開發者和前端開發者追求的的話題,從早期的cordova、ionic,到現在的react native、weex、kotlin native和flutter等,能夠說現在的跨平臺框架可謂百花齊放,很有一股推倒原生開發者的勢頭。vue

若是要對目前的跨平臺的方案進行一個總結,大體能夠分爲如下幾個流派: JavaScript流派:這一流派中,最明顯的特徵是使用JavaScript做爲編程語言,react native、weex均屬於這一流派。和其餘跨平臺方案相比,JavaScript在跨平臺開發中,使用者最多,大有「一統天下」的趨勢。 VM虛擬機:與其餘方案不一樣,kotlin提供的kotlin-native技術擁有本身的VM,能夠同時支持Android、iOS 和 Web 開發。 Flutter:Futter是Google開源的移動跨平臺UI框架,使用的是Google本身的Dart編程語言,因爲是Google推出的產品,於是也受到不少開發者的喜好。node

不過,綜合對比開發現,目前最火的跨平臺開發方案,特別是已經商用的跨平臺開發框架中,react native無疑是老大,其次是Weex(畢竟是阿里的產品),最後多是最近才火起來的Flutter。react

React Native

曾經,React Native的口號是「Learn once, write anywhere」,這句話表明了FaceBook對React Native設計的初衷:學習 react ,同時掌握 web 與 app 兩種開發技能。android

藉助FaceBook旗下的React的設計模式 , React Native使用的UI渲染、動畫效果、網絡請求等會轉換成原生端的實現。也就是說,開發者編寫的js代碼,經過 react native 的中間層(JavaScriptCore)轉化爲原生控件和操做,這就最大程度的接近原生應用的用戶體驗,並提升了開發的效率。webpack

React Native的結構

React Native的跨平臺是實現主要由三層構成,其中 C++ 實現的動態連結庫(.so),做爲中間適配層橋接,實現了js端與原生端的雙向通訊交互。ios

這裏最主要是封裝了 JavaScriptCore 執行js的解析,而 react native 運行在JavaScriptCore中,因此不存在瀏覽器兼容的問題。其結構如以下圖:web

原理

React Native實現的原理其實就是利用JS 調用Native 端的組件,並使用Native的組件來繪製界面,從而達到媲美原生應用的效果。apache

和前端開發不一樣,React Native 所使用的標籤並非真實的控件,React Native提供的組件會Dom 轉換爲Native的控件進行渲染。例如<Text> 標籤會被轉換爲Android 中對應 TextView 控件。編程

須要說明的是,在React Native 中,JS端是運行在獨立的線程中(稱爲JS Thread ),JS Thread 做爲單線程邏輯,不可能處理耗時的操做。那麼如 fetch 、圖片加載 、 數據持久化等操做,在 Android 中實際對應的是 okhttp 、Fresco 、SharedPreferences等。而跨線程通訊,也意味着 Js Thread 和原生之間交互與通信是異步的。

由此能夠看出,跨平臺的關鍵在於C++層,開發人員大部分時候,只專一於JS 端的代碼實現便可,無線瞭解底層的實現細節。 而若是要實現和原生模塊的交互,只須要在原生端提供的各類 Native Module 模塊(如網絡請求,ViewGroup控件)便可,而後經過 JS 端提供的各類 JS Module(如JS EventEmiter模塊)來實現調用。而且這些調用都會在C++實現的so中保存起來,雙方的通信經過C++中的保存的映射,最終實現兩端的交互,通訊的數據和指令,在中間層會被轉爲String字符串傳輸,雙向的調用流程以下圖。

打包與發佈

在React Native混合項目中,JS代碼會被打包成一個 bundle 文件,自動添加到 App 的資源目錄下。react native 的打包腳本目錄爲/node_modules/react-native/local-cli,打包最後會經過 metro 模塊壓縮 bundle 文件。而bundle文件只會打包js代碼,天然不會包含圖片等靜態資源,因此打包後的靜態資源,實際上是被拷貝到對應的平臺資源文件夾中。

舉個例子,react native 項目會將圖片存儲在根目錄下的 img/pic/logo.png 的資源,編譯時,會被重命名後,根據大小 merged 到對應的是drawable目錄下,修更名稱爲img_pic_logo.png。

Weex

Weex是阿里巴巴開源的一套移動跨平臺開發框架,可以完美兼顧性能與動態性,讓移動開發者經過簡捷的前端語法寫出Native級別的性能體驗,並支持iOS、安卓、YunOS及Web等多端部署。目前,使用Weex框架的多半是阿里系的產品和一些創業的公司。

Weex架構

Weex的口號是「Write once, run everywhere」,Weex使用的耳熟能詳的Vue,阿里的思惟是:寫個 vue 前端,順便完成一個apk 和 ipa,但其實仍是有差距的。Weex支持 web、android、ios 三端,原生端一樣經過中間層轉化,將控件和操做轉化爲原生邏輯來提升用戶體驗。。

在 Weex的架構層次中,主要包括三大部分:JS Bridge、Render、Dom,分別對應WXBridgeManager、WXRenderManager、WXDomManager,三部分經過WXSDKManager統一管理。其中 JS Bridge 和 Dom 都運行在獨立的 HandlerThread 中,而 Render 運行在 UI 線程。關於Weex架構分層的內容讀者能夠自行查看官方資料的介紹。

其中,JS Bridge 主要用來和 JS 端實現進行雙向通訊,好比把 JS 端的 dom 結構傳遞給 Dom 線程。Dom 主要是用於負責 dom 的解析、映射、添加等等的操做,最後通知UI線程更新。而 Render 負責在UI線程中對 dom 實現渲染。

實現原理

和 React Native同樣,Weex 全部的標籤也不是真實控件,Weex的標籤只不過是JS 代碼中所生成存的 dom,最後都是由 Native 端解析,再獲得對應的Native控件渲染。如 Android 中 <text> 標籤對應 WXTextView 控件。

Weex 中文件默認爲 .vue ,而 vue 文件是被沒法直接運行的,因此 vue 會被編譯成 .js 格式的文件,Weex SDK會負責加載渲染這個js文件。Weex能夠作到跨三端的原理在於:在開發過程當中,代碼模式、編譯過程、模板組件、數據綁定、生命週期等上層語法是一致的。

不一樣的是,在 JS Framework 層的最後,web 平臺和 Native 平臺,對 Virtual DOM 執行的解析方法是有區別的,在渲染真實 UI 的時候調用的接口也不一樣的。

Weex 表面上是一個客戶端技術,但實際上它串聯起了從本地開發、雲端部署到分發的整個鏈路。開發者首先可在本地像編寫 web 頁面同樣編寫一個 app 的界面,而後經過命令行工具將之編譯成一段 JavaScript 代碼,生成一個 Weex 的 JS bundle;同時,開發者能夠將生成的 JS bundle 部署至雲端,而後經過網絡請求或預下發的方式加載至用戶的移動應用客戶端;在移動應用客戶端裏,Weex SDK 會準備好一個 JavaScript 執行環境,而且在用戶打開一個 Weex 頁面時在這個執行環境中執行相應的 JS bundle,並將執行過程當中產生的各類命令發送到 native 端進行界面渲染、數據存儲、網絡通訊、調用設備功能及用戶交互響應等功能;同時,若是用戶但願使用瀏覽器訪問這個界面,那麼他能夠在瀏覽器裏打開一個相同的 web 頁面,這個頁面和移動應用使用相同的頁面源代碼,但被編譯成適合Web展現的JS Bundle,經過瀏覽器裏的 JavaScript 引擎及 Weex SDK 運行起來的。

其中, Native 加載bundle 文件大體經歷瞭如下階段:

  • weex 接收到 js 文件之後,JS Framework 根據文件爲 Vue 模式,會調用weex-vue-framework 中提供的createInstance方法建立實例。
  • createInstance 中會執行 Js Entry 代碼裏 new Vue() 建立一個組件,經過其 render 函數建立出 Virtual DOM 節點。
  • 由JS V8 引擎上解析 Virtual DOM ,獲得 Json 數據發送至 Dom 線,這裏輸出 Json 也是方便跨端的數據傳輸。
  • Dom 線程解析 Json 數據,獲得對應的 WxDomObject,而後建立對應的WxComponent 提交 Render 。
  • Render在原生端最終處理處理渲染任務,並回調裏JS方法。

相比React Native,Weex主要是在JS V8的引擎上多了 JS Framework 承當了重要的職責,使得上層具有統一性,能夠支持跨三個平臺。總的來講它主要負責是:管理Weex的生命週期,解析JS Bundle,轉爲Virtual DOM,再經過所在平臺不一樣的API方法,構建頁面;進行雙向的數據交互和響應。

打包與發佈

在打包方案上,Weex和React Native都經過 Webpack 來打包bundle 文件的。不過,React Native打包若是不作拆分,打出的包是很大的,於是會本身制定一些拆包的規則。而Weex 做爲React Native以後出現的跨平臺實現方案,天然能夠站在前人的肩膀上優化問題,好比:Bundle文件過大問題。 Weex 選擇使用JS Framework 集成到 WeexSDK的方式,必定程度減小了JS Bundle的體積,使得 bundle 裏面只保留業務代碼。

打包時,weex 是經過 webpack 打包出 bundle 文件的。bundle 文件的打包和 entry.js 文件的配置數量有關,默認狀況下以後一個 entry 文件,天然也就只有一個bundle文件。   在 weex 項目的 webpack.common.conf.js 中能夠看到,其實打包也是區分了 webConfig 和 weexConfig 的不一樣打包方式。

Flutter

Flutter是Google用以幫助開發者在Ios和Android兩個平臺開發高質量原生應用的全新移動UI框架。與 React Native 和 Weex 框架使用的Javascript 技術不一樣,Flutter 使用的是全新的編程語言Drat,因此執行時並不須要 Javascript 引擎,但實際效果最終也經過原生渲染。

Flutter框架

Flutter框架主要分爲 Framework 和 Engine兩層,咱們基於Framework 開發App主要運行在 Engine 上。Engine 是 Flutter 的獨立虛擬機,由它適配和提供跨平臺支持,目前猜想 Flutter 應用程序在 Android 上,是直接運行 Engine 上 因此在是不須要Dalvik虛擬機。其架構圖以下圖所示:

得益於 Engine 層,Flutter 甚至不使用移動平臺的原生控件, 而是使用本身 Engine 來繪製 Widget (Flutter的顯示單元),而 Dart 代碼都是經過 AOT 編譯爲平臺的原生代碼,因此 Flutter 能夠 直接與平臺通訊,不須要JS引擎的橋接。

而Flutter惟一要求系統提供的是canvas,用以實現UI的繪製。不過,Flutter 上 Android 自帶了 Skia,Skia是一個 2D的繪圖引擎庫,跨平臺,因此能夠被嵌入到 Flutter的 iOS SDK中,也使得 Flutter Android SDK要比 iOS SDK小不少。

對比

下面對上面介紹的幾大框架進行一個簡單的對比,以方便讀者進行對比學習。

對比類型 React Native Weex Flutter
實現技術 JavaScript JavaScript 原生編碼,無橋接
引擎 JS V8 JSCore Flutter engine
使用語言 React Vue Dart
bundle文件大小 默認單1、較大 較小、多頁面可多文件 不須要
上手難度 稍高大 容易 簡單
框架難度 較重 較輕
支持對象 Android、IOS Android、IOS、Web Android、IOS

包大小對比

上面Apk大小是經過 react-native init、weex create 和 flutter 建立出的工程後,直接不添加任何代碼,打包出來的 release 簽名 apk 大小。從下圖能夠看出,其中大比例都是在so庫。

附: React Native中文網 Weex官方文檔 Flutter中文社區

相關文章
相關標籤/搜索