背景與問題
- 中小公司維護一個App的成本好高呀,有沒有辦法可以降低成本的可能性,但是又不想讓代碼缺少維護?
- 有沒有方案可以實現一份代碼可以運行在多個平臺,減少溝通成本呢?
問題方案選擇
各公司都開始關注和使用跨端方案【包括大廠阿里巴巴以及騰訊】目前主流的跨端方案主要分為兩種:一種是將JavaScriptCore引擎作為虛擬機的方案,代表框架是React Native;另一種是使用非JavaScriptCore虛擬機的方案,代表框架是Flutter。【其中還有一種是使用Webview的方案-待會也會講解到】
使用跨端方案進行開發,必然會替代原有平臺的開發技術,所以我們在選擇跨端方案時,不能只依賴於某幾項指標,比如編程語言、性能、技術架構等,來判斷是否適合自己團隊和產品,更多的還要考慮開發效率、社區支持、構建發佈、 DevOps、 CI 支持等工程化方面的指標。
作為一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是一個我的iOS交流群:413038000,不管你是大牛還是小白都歡迎入駐 ,分享BAT,阿里面試題、面試經驗,討論技術, 大家一起交流學習成長!
目前本公司其它項目採用的是Flutter和Swift混編,感覺下一步本負責項目也要進入這個模式,所以開啟Flutter之旅。
希望通過本篇博客,大家能夠理解為什麼選擇Flutter,以及幾種跨平臺的區別,歡迎關注與點贊,彼此共同進步,謝謝!!!
方案特點原理
方案一:Webview
Webview是基於JavaScript和WebView的跨平臺。主要工作在Webkit中完成
最早出現的跨平臺框架是基於JavaScript和WebView,代表框架有PhoneGap,Apache Cordova,Ionic等。
WebView主要是通過HTML來構建自己的界面,再將其顯示在各個平臺的WebView中,但是它默認是不能調用本地的一些服務的【比如藍牙、相機等】所以需要調用JavaScript進行橋接調用Native的一些代碼來完成某些功能。但是根據本人親自對WebView的使用,WebView的性能並不夠理想,而且開發過程中的坑也比較多。
下圖是WebView的原理圖--認真看下
方案二:React Native
React Native【簡稱RN】是Facebook於2015年4月開源的跨平臺移動應用開發框架,,是Facebook早先開源的JS框架 React 在原生移動應用平臺的衍生產物,目前支持iOS和安卓兩大平臺。
RN使用JavaScript語言類似於HTML的JSX,以及CSS來開發移動應用,並且在保留基本渲染能力的基礎上,用原生自帶的UI組件實現核心的渲染引擎,從而保證了良好的渲染性能。
但是,由於RN的本質是通過JavaScript VM調用原生接口,通信相對比較低效,而且是間接通過原生進行渲染的。
方法三:Flutter
Flutter是谷歌的移動UI框架,可以快速在iOS和Android上構建高質量的原生用戶界面。 Flutter可以與現有的代碼一起工作。在全世界,Flutter正在被越來越多的開發者和組織使用,並且Flutter是完全免費、開源的。
總體來說,相比於React Native框架,Flutter的優勢最主要體驗在性能、開發效率和體驗兩大方面。
React Native所使用的JavaScriptCore,原本用在瀏覽器中,用於解釋執行網頁中的JavaScript代碼。為了兼容Web標準留下來的歷史包袱,無法專門針對移動端進行性能優化。Flutter卻不一樣,它一開始就拋棄了歷史包袱,使用全新的Dart語言編寫,同時支持AOT和JIT兩種編譯方式,而沒有采用HTML/CSS/JavaScript組合方式開發,在執行效率上明顯高於JavaScriptCore。
除了編程語言的虛擬機,Flutter的優勢還體現於UI框架的實現上。它重寫了UI框架,從UI控件到渲染,全部重寫實現了,依賴Skia圖形庫和系統圖形繪製相關的接口,保證了不同平臺上能有相同的體驗。
Flutter利用Skia繪圖引擎,直接通過CPU、GPU進行繪製,不需要依賴任何原生的控件。【Andriod操作系統中,編寫的原生控件中實際上也是依賴於Skia進行繪製,所以Flutter在某些Andriod操作系統上甚至還要高於原生-因為原生Andriod中的Skia必須隨著操作系統進行更新,而Flutter SDK中總是保持最新的】
Flutter對比優勢
下面用andriod平臺來對比:Flutter、原生與RN等平臺的對比,可以看出除了原生開發,Flutter的性能更高
Flutter剖析
Flutter繪製原理圖
- GPU將信號同步到UI線程
- UI線程用Dart來構建圖層樹
- 圖層樹在GPU線程中合成
- 合成後的視圖數據提供給SKia引擎
- Skia引擎通過OpenGL或者Vulkan將顯示內容提供給GPU,所以有兩個GPU構成一個閉環
Flutter和React Native的本質區別:
- React Native 只能通過JavaScript虛擬機擴展調用系統組件,由iOS 和 Andriod系統組件的渲染
- Flutter是自己完成了組件渲染的閉環
幀率與刷新率
1、基礎知識
幀率【fps】:Frame Per Second
刷新率:顯示器的頻率,比如iPhone 的 60HZ等
拓展:
我們為什麼能看到類似於動畫的效果呢?
1、這是因為它播放的速度非常快,研究表明: p 當圖片連續播放的頻率超過16幀(16張圖片),人眼就會感覺非常流暢,當少於16幀時,會感覺到卡頓
2、所以我們平時看到的電影,通常都是24幀或者30幀的(李安之前拍攝120幀的電影,目的就是讓圖片間隔更小,畫面更加的流暢)
複製代碼
2、幀率與刷新率的關係
CPU/GPU 向 Buffer 中生成圖像,屏幕從 Buffer 中取圖像、刷新後顯示。
這是一個典型的生產者---消費者模型。理想的情況下幀率和刷新率相等,每繪製一幀,屏幕顯示一幀,但是實際情況下往往它們的大小是不同的。如果沒有鎖來控制同步,很容易出現問題。例如當幀率大於刷新頻率,當屏幕還沒有刷新第 n-1幀的時候,GPU 已經在生成第 n 幀了。從上往下開始覆蓋第n - 1幀的數據,當屏幕開始刷新第n - 1幀的時候,Buffer中的數據上半部分是第n幀數據,下半部分是第n - 1 幀的數據。顯示出來的圖像就是上下部分出現明顯偏差,稱之為“撕裂”。
雙重緩存【Double Buffer】
1、基本概念
為了解決單緩存的“撕裂”問題,就出現了雙重緩存和Vsync。
兩個緩存區分別為 Back Buffer 和 Frame Buffer。
GPU 向 Back Buffer 中寫數據,屏幕從 Frame Buffer 中讀數據。
VSync 信號負責調度從 Back Buffer 到 Frame Buffer 的複製操作。當然底層不是通過複製,而是通過交換內存地址方式,所以可以瞬間完成,效率是非常高的;
工作流程:
- 在某個時間點,一個屏幕刷新週期完成,VSync 信號產生,先完成複製操作,然後通知 CPU/GPU 繪製下一幀圖像。
- 複製操作完成後屏幕開始下一個刷新週期,即將剛複製到 Frame Buffer 的數據顯示到屏幕上。
- 在這種模型下,只有當 VSync 信號產生時,CPU/GPU 才會開始繪製。
**2、存在的問題
**
雙重緩存的缺陷在於:當 CPU/GPU 繪製一幀的時間過長(比如超過16ms)時,會產生 Jank(畫面停頓,甚至空白)。
藍色代表 CPU 生成 Display List;
綠色代表 GPU 執行 Display List 中的命令從而生成幀;
黃色代表生成幀完成,在屏幕上顯示;
CPU生成藍色B的數據,由GPU進行B的繪製,但是這個過長由於過長,那麼第二個A就產生了Jank。
B在屏幕上顯示之後,發出Vsync信號,A開始繪製,但是由於繪製時間過長,第二個B位置又產生了Jank
渲染引擎Skia
Skia(全稱Skia Graphics Library(SGL))是一個由C++編寫的開源圖形庫,Skia就是 Flutter向 GPU提供數據的途徑。
Skia 已然是 Android 官方的圖像渲染引擎了,因此 Flutter AndroidSDK 無需內嵌 Skia 引擎就可以獲得天然的 Skia 支持; 而對於 iOS 平臺來說,由於 Skia 是跨平臺的,因此它作為 Flutter iOS 渲染引擎被嵌入到 Flutter 的 iOS SDK 中,替代了 iOS 閉源的 Core Graphics/Core Animation/Core Text,這也正是 Flutter iOS SDK 打包的 App 包體積比Android 要大一些的原因。
底層渲染能力統一了,上層開發接口和功能體驗也就隨即統一了,開發者再也不用操心平臺相關的渲染特性了。也就是說,Skia 保證了同一套代碼調用在Android 和 iOS 平臺上的渲染效果是完全一致的。
總結
從11月份開始進軍Flutter領域,本人的博客也會由iOS 底層探尋 + Flutter初體驗 + 小程序的研發為主,歡迎大家關注及點贊,共同在移動端提升自己的專業技能+才幹,共勉!!!
作為一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是一個我的iOS交流群:413038000,不管你是大牛還是小白都歡迎入駐 ,分享BAT,阿里面試題、面試經驗,討論技術, 大家一起交流學習成長!
作者:國孩
鏈接:https://juejin.cn/post/6902707237345558542
來源:掘金