本節內容轉載于[Flutter中文網](https://flutterchina.club/)
[TOC]
# 原生開發
原生開發指開發某一個應用平臺(如Android或iOS)所特有的應用,使用相應平臺支持的開發工具和語言,并直接調用系統提供的SDK API。
原生開發的優勢:
* 可訪問平臺全部功能(GPS、攝像頭)
* 速度快、性能高、可實現復雜動畫及繪制
* 用戶體驗好
原生開發缺點:
* 平臺特定,開發成本高,不同平臺需要維護不同代碼,人力成本隨之增大
* 內容固定,動態化弱,新功能需發版才能更新
目前業務場景中的兩個需求:
1、動態化內容需求增大
2、業務需求變化快,人力開發成本變大
針對這兩個問題,誕生了一些跨平臺的動態化框架。
# 跨平臺開發
時至今日,已經有很多跨平臺框架,根據其原理,主要分為三類:
* H5+原生混合開發(Cordova、Ionic、微信小程序)
* JavaScript開發+原生渲染 (React Native、Weex、快應用)
* 自繪UI+原生(QT for mobile、Flutter)
## H5+原生混合開發
框架:Cordova、Ionic、微信小程序等
混合開發的原理是將APP的一部分需要動態變動的內容通過H5來實現,通過原生的網頁加載控件WebView (Android)或WKWebView(iOS)來加載。H5部分是可以隨時改變而不用發版,動態化需求能滿足;同時由于H5代碼只需要一次開發,就能同時在Android和iOS兩個平臺運行,可以減小開發成本。
混合開發中H5代碼運行在WebView中,而WebView本質是一個瀏覽器內核,其JavaScript運行在一個權限受限的沙箱中,所以對于大多數系統能力沒有訪問權限,如無法訪問文件系統、不能使用藍牙等。
對于H5不能實現的功能,都需要原生去做。混合框架一般都會在原生代碼中預先實現一些訪問系統能力的API, 暴露給WebView以供JavaScript調用。
WebView就成了JavaScript與原生API之間通信的橋梁,主要負責JavaScript與原生之間傳遞調用消息。消息的傳遞必須遵守一個標準的協議,來規定消息的格式與含義,我們把依賴于WebView的用于在JavaScript與原生之間通信并實現了某種消息傳輸協議的工具稱之為**WebView JavaScript Bridge**, 簡稱**JsBridge**,JsBridge是混合開發框架的核心。
### 優點與缺點
優點:
1、H5加載,可以實現動態化,無需發版即可更新內容
2、一套代碼開發,開發成本低
缺點:
1、性能不好,無法高效渲染復雜的用戶界面或動畫
2、無法直接訪問部分系統能力(如文件系統、藍牙等)
## JavaScript開發+原生渲染
框架:Reactive Native、Weex及快應用
### 響應式編程
React中有一個重要思想:狀態改變則UI隨之自動改變。React框架的工作就是響應用戶狀態改變的事件,重新構建用戶界面,React是典型的**響應式**編程。
React中響應式原理如下:
* 1、開發者只需關注狀態轉移,當狀態發生變化時,React框架會自動根據新的狀態重新構建UI。
* 2、React框架在接收到用戶狀態改變的通知后,根據當前渲染樹,結合最新的狀態改變,通過Diff算法,計算出樹中變化的部分,然后只更新變化的部分(DOM操作),從而避免整棵樹重構,提高性能。
需要注意的是,第二步中狀態變化后,React框架并不會立即去計算并渲染DOM樹的變化部分。相反,React會在DOM的基礎上建立一個抽象層,即**虛擬DOM**樹,對數據和狀態所做的任何改動,都會被自動且高效的同步到虛擬DOM,最后再批量同步到真實DOM中,而不是每次改變都去操作一下DOM。因為在瀏覽器中每一次DOM操作都有可能引起瀏覽器的重繪或回流,瀏覽器的重繪和回流都是比較昂貴的操作,如每一次改變都直接對DOM進行操作,會帶來性能問題,而批量操作只會觸發一次DOM更新。
### Reactive Native原理
Reactive Native是React在原生移動應用平臺的衍生產物,兩者的主要區別在于:React中虛擬DOM最終會映射為瀏覽器DOM樹,而Reactive Native中虛擬DOM會通過JavaScripCore映射為原生控件樹。
JavaScriptCore是一個JavaScript解釋器,在ReactiveNative中主要有兩個作用:
* 為JavaScript提供運行環境
* 是JavaScript與原生應用間的通信橋梁,作用和JsBridge一樣(在iOS中,很多JsBridge的實現都是基于JavaScriptCore)
在ReactiveNative中將虛擬DOM映射稱為原生控件需要兩步:
* 布局消息傳遞: 將虛擬DOM布局信息傳遞給原生
* 原生根據布局信息通過對應的原生控件渲染控件樹
### Weex與快應用
Weex思想及原理與ReactiveNative類似,不同的是語法層面,Weex支持Vue語法和Rax語法。
快應用是華為、小米、OPPO、魅族等國內9大主流手機廠商共同制定的輕量級應用標準,目標直指微信小程序,它也是采用JavaScript語言開發,原生控件渲染,與React Native和Weex相比主要有兩點不同:
* 快應用自身不支持Vue或React語法,其采用原生JavaScript開發(開發框架和微信小程序很像,值得一提的是小程序目前已經可以使用Vue語法開發(mpvue))
* React Native和Weex的渲染/排版引擎是集成到框架中的,每一個APP都需要打包一份,安裝包體積較大;而快應用渲染/排版引擎是集成到ROM中的,應用中無需打包,安裝包體積小,正因如此,快應用才能在保證性能的同時做到快速分發。
### 優點與缺點
優點:
1、原生控件渲染,性能比混合應用中的H5提高很多
2、使用Web開發技術棧,只需要維護一份代碼,開發成本相對較低
3、動態化較好,支持熱更新
缺點:
1、渲染時需要JavaScript與原生之間進行通信,某些場景可能因通信頻繁導致卡頓
2、JavaScript為腳本語言,執行時需要JIT(Just In Time),執行效率和AOT(Ahead Of Time)代碼仍有差距
3、渲染依賴原生控件,不同平臺控件需要單獨維護,系統更新時,社區控件可能會滯后。除此之外,控件系統也會受到原生UI系統限制,比如解決手勢沖突問題。
## 自繪UI+原生
通過在不同平臺實現一個統一接口的渲染引擎來繪制UI,而不依賴系統原生控件,所以可以做到不同平臺UI的一致性。自繪引擎解決的是UI的跨平臺問題,涉及其它系統能力調用,依然要使用原生開發。
### 優點與缺點
優點:
1、直接調用系統API來繪制UI,性能好
2、UI渲染不依賴原生控件,不需要根據不同平臺的控件單獨維護一套組件庫,代碼易維護
3、組件庫是同一套代碼、同一個渲染引擎,在不同平臺組件上,顯示外觀可以做到高保真和高一致性;
4、不依賴原生控件,布局系統更加靈活
缺點:
動態性不足,自繪UI系統一般采用AOT模式編譯其發布包,不能像使用JIT開發語言框架那樣動態下發代碼
### QT Mobile
Qt是一個1991年由Qt Company開發的跨平臺C++圖形用戶界面應用程序開發框架。2008年,Qt Company科技被諾基亞公司收購,Qt也因此成為諾基亞旗下的編程語言工具。2012年,Qt被Digia收購。
2014年4月,跨平臺集成開發環境Qt Creator 3.1.0正式發布,實現了對于iOS的完全支持,新增WinRT、Beautifier等插件,廢棄了無Python接口的GDB調試支持,集成了基于Clang的C/C++代碼模塊,并對Android支持做出了調整,至此實現了全面支持iOS、Android、WP,它提供給應用程序開發者構建圖形用戶界面所需的所有功能。
QT沒有流行起來的原因所在:
* QT移動開發社區太小,學習資料不足,生態不好
* 官方推廣不利,支持不夠
* 移動端發力較晚,市場已被其它動態化框架占領(Hybrid和RN)
* 在移動開發中,C++開發和Web開發棧相比有著先天的劣勢,直接結果就是QT開發效率太低
### Flutter
Flutter是Google發布的一個用于創建跨平臺、高性能移動應用的框架。Flutter和QT mobile一樣,都沒有使用原生控件,相反都實現了一個自繪引擎,使用自身的布局、繪制系統。
## 總結
| 技術類型 | UI渲染方式 | 性能 | 開發效率 | 動態化 | 框架代表 |
| --- | --- | --- | --- | --- | --- |
| H5+原生 | WebView渲染 | 一般 | 高 | 支持 | Cordova、Ionic |
| JavaScript+原生渲染 | 原生控件渲染 | 好 | 中 | 支持 | RN、Weex |
| 自繪UI+原生 | 調用系統API渲染 | 好 | Flutter高, QT低 | 默認不支持 | QT、Flutter |
Flutter的Release包默認是使用Dart AOT模式編譯的,所以不支持動態化,但Dart還有JIT或snapshot運行方式,這些模式都是支持動態化的。
- 導讀
- Java知識
- Java基本程序設計結構
- 【基礎知識】Java基礎
- 【源碼分析】Okio
- 【源碼分析】深入理解i++和++i
- 【專題分析】JVM與GC
- 【面試清單】Java基本程序設計結構
- 對象與類
- 【基礎知識】對象與類
- 【專題分析】Java類加載過程
- 【面試清單】對象與類
- 泛型
- 【基礎知識】泛型
- 【面試清單】泛型
- 集合
- 【基礎知識】集合
- 【源碼分析】SparseArray
- 【面試清單】集合
- 多線程
- 【基礎知識】多線程
- 【源碼分析】ThreadPoolExecutor源碼分析
- 【專題分析】volatile關鍵字
- 【面試清單】多線程
- Java新特性
- 【專題分析】Lambda表達式
- 【專題分析】注解
- 【面試清單】Java新特性
- Effective Java筆記
- Android知識
- Activity
- 【基礎知識】Activity
- 【專題分析】運行時權限
- 【專題分析】使用Intent打開三方應用
- 【源碼分析】Activity的工作過程
- 【面試清單】Activity
- 架構組件
- 【專題分析】MVC、MVP與MVVM
- 【專題分析】數據綁定
- 【面試清單】架構組件
- 界面
- 【專題分析】自定義View
- 【專題分析】ImageView的ScaleType屬性
- 【專題分析】ConstraintLayout 使用
- 【專題分析】搞懂點九圖
- 【專題分析】Adapter
- 【源碼分析】LayoutInflater
- 【源碼分析】ViewStub
- 【源碼分析】View三大流程
- 【源碼分析】觸摸事件分發機制
- 【源碼分析】按鍵事件分發機制
- 【源碼分析】Android窗口機制
- 【面試清單】界面
- 動畫和過渡
- 【基礎知識】動畫和過渡
- 【面試清單】動畫和過渡
- 圖片和圖形
- 【專題分析】圖片加載
- 【面試清單】圖片和圖形
- 后臺任務
- 應用數據和文件
- 基于網絡的內容
- 多線程與多進程
- 【基礎知識】多線程與多進程
- 【源碼分析】Handler
- 【源碼分析】AsyncTask
- 【專題分析】Service
- 【源碼分析】Parcelable
- 【專題分析】Binder
- 【源碼分析】Messenger
- 【面試清單】多線程與多進程
- 應用優化
- 【專題分析】布局優化
- 【專題分析】繪制優化
- 【專題分析】內存優化
- 【專題分析】啟動優化
- 【專題分析】電池優化
- 【專題分析】包大小優化
- 【面試清單】應用優化
- Android新特性
- 【專題分析】狀態欄、ActionBar和導航欄
- 【專題分析】應用圖標、通知欄適配
- 【專題分析】Android新版本重要變更
- 【專題分析】唯一標識符的最佳做法
- 開源庫源碼分析
- 【源碼分析】BaseRecyclerViewAdapterHelper
- 【源碼分析】ButterKnife
- 【源碼分析】Dagger2
- 【源碼分析】EventBus3(一)
- 【源碼分析】EventBus3(二)
- 【源碼分析】Glide
- 【源碼分析】OkHttp
- 【源碼分析】Retrofit
- 其他知識
- Flutter
- 原生開發與跨平臺開發
- 整體歸納
- 狀態及狀態管理
- 零碎知識點
- 添加Flutter到現有應用
- Git知識
- Git命令
- .gitignore文件
- 設計模式
- 創建型模式
- 結構型模式
- 行為型模式
- RxJava
- 基礎
- Linux知識
- 環境變量
- Linux命令
- ADB命令
- 算法
- 常見數據結構及實現
- 數組
- 排序算法
- 鏈表
- 二叉樹
- 棧和隊列
- 算法時間復雜度
- 常見算法思想
- 其他技術
- 正則表達式
- 編碼格式
- HTTP與HTTPS
- 【面試清單】其他知識
- 開發歸納
- Android零碎問題
- 其他零碎問題
- 開發思路