來源 | OSCHINA 社區
一,需求背景:
APP 發布到市場后,難免會遇到嚴重的 BUG 阻礙用戶使用,因此有在不發布新版本 APP 的情況下使用熱更新技術立即修復 BUG 需求。原生 APP(例如:Android & IOS)的熱更新需求已經比較成熟,但 Flutter 技術棧目前還缺少類似的技術方案,因此 Flutter 研發團隊,也需要類似的熱更新技術。
二,Flutter 熱更新技術方向分析:
經過分析目前可能有三種可行的方案:1)類似 RN 框架;2)頁面動態組件框架;3)Dart 虛擬機定制方案;
方案名稱 | 原理 | 優點 | 缺點 | 開源方案 |
---|---|---|---|---|
類似 RN 的方案 | 用 JS 以 Flutter 語法寫 dart,然后用 JavaScript 把 XML DSL 轉為 Flutter 的原子 widget 組件,然后再讓 Flutter 來渲染 | 由于 ios 系統內置支持 js,ios 上完全可以實現更新 | 1) 由于跨語言執行,對于性能有影響;學習成本高 2) Android 端需要額外引入 JS 庫 | 手 Q 的 MXFlutter,58 同城的 Fair |
- | - | - | - | - |
頁面動態組件方案 | 編譯期時插樁 / 預埋好 DynamicWidget 到代碼中,然后動態下發 Json 數據,通過協定好的語義匹配到 JSON 內的數據,動態替換 Widget 內容來實現更新 | 能支持 Android/iOS 兩端的更新 | 1)UI 更新相對較容易,業務邏輯動態化較麻煩;2)語義解析器開發成本相對較大,且不易維護 3)需要一整套前后端服務和工具 | 天貓的 Tangram,淘寶的 DinamicX 等 |
Dart 虛擬機定制方案 | 通過分析 Dart 虛擬機的原理,修改 Flutter Engine 層 Java/C++ 代碼實現熱更新的目標; | 性能影響小,動態性很高,技術上可以替換所有 Flutter 頁面(包括 UI,邏輯,資源文件) | 由于使用的是定制引擎,需要維護不同版本的 Flutter 引擎代碼; | 未開源 |
因為其他方式都有開源的示例,本案將重點以第三種 “Dart 虛擬機定制方案” 為目標,做方案的研究講解。
三,預備知識
在開始了解技術方案之前,需要提前了解一些相應的技術概念:
3.1 Flutter 編譯模式
Flutter 開發語言是 Dart,它的編譯模式來自 Dart 的編譯模式,主要有 JIT (Just In Time) 和 AOT (Ahead Of Time)。
編譯模式名稱 | 特點 | 優點 | 缺點 |
---|---|---|---|
JIT | 即時編譯,典型例子 V8,它可以即時編譯運行 JS,只需要輸入源代碼字符串,就可以編譯運行代碼 | 可以動態下發和執行代碼,不用管 CPU 架構,可以提供動態化內容 | 1, 大量字符串代碼讓 JIT 編譯器花費時間和內存;2, 性能不好; |
- | - | - | - |
AOT | 預先編譯,典型例子 C/C++,通過 GCC 編譯成二進制代碼,然后安裝取得權限后才可以加載執行 | 事先編譯好的,加載和執行速度快 | 1, 編譯時區分 CPU 架構;2, 生成的二進制代碼包比較大;3, 二進制代碼需要取得權限才可以執行,無法在 ios 系統上動態更新 |
Flutter 編譯模式有:Debug,Release,Profile;
Flutter 編譯模式 | 特點 |
---|---|
Debug | 對應 JIT 模式,支持設備和模擬器;打開了斷言,支持快速開發,支持 HotReload;并未對包大小,執行速度做優化; |
- | - |
Release | 對應 AOT 模式,支持真機,不支持模擬器;禁止了所有斷言調試信息;對包大小,啟動和執行速度進行了優化; |
Profile | 類似 Release 模式,保留了一些調試功能,幫助性能分析; |
3.2 Flutter 編譯產物分析
Flutter 下的 iOS/Android 工程本質上是一個標準的 iOS/Android 的工程;IOS 平臺: Flutter 通過在 BuildPhase 中添加 shell (xcode_backend.sh) 來生成和嵌入 App.framework 和 Flutter.framework 到 ios; Android 平臺: Flutter 通過 gradle 來添加 flutter.jar 和編譯完的二進制文件添加到 Android;
3.2.1 引擎層結構分析:
3.2.2 Android 編譯產物的分析
3.2.3 IOS 編譯產物的分析
四,熱更新技術方案分析
4.1 業務代碼分析
根據 “3.3.1” ~“3.3.2” 的分析可以確定無論是 IOS 還是 Android APP 業務代碼都是由四個段組成:kDartVmSnapshotData、kDartVmSnapshotInstructions、kDartIsolateSnapshotData、kDartIsolateSnapshotInstructions;理論上只要能動態替換加載的代碼段 & 數據段代碼即可實現目標。
名稱 | 注釋 | 作用 | 注釋 |
---|---|---|---|
kDartIsolateSnapshotData | Dart isolate 數據段 | 類信息,全局變量,函數指針等 | 允許動態下發 |
- | - | - | - |
kDartIsolateSnapshotInstructions | Dart isolate 指令段 | 包含由 Dart isolate 執行的 AOT 代碼 | IOS 不允許動態下發 |
kDartVmSnapshotData | vm isolate 數據段 | isolate 之間共享的 Dart 堆 (heap) 的初始狀態 | 允許動態下發 |
kDartVmSnapshotInstructions | vm isolate 指令段 | 包含 VM 中所有 Dart isolate 之間共享的通用程序的 AOT 指令 | IOS 不允許動態下發 |
注釋:isolate, snapshot, vm isolate 含義解釋如下:
名稱 | 含義 |
---|---|
isolate | Dart 是單線程,isolate 跟線程差不多,可以理解為 Dart 中的線程。isolate 與線程的區別:線程與線程之間是共享內存的,而 isolate 和 isolate 之間是內存不共享的。不存在鎖競爭問題,兩個 Isolate 完全是兩條獨立的執行線,且每個 Isolate 都有自己的事件循環,它們之間只能通過發送消息通信,所以它的資源開銷低于線程。 |
- | - |
snapshot | 將類信息、全局變量、函數指令直接以序列化的方式存在磁盤中,稱為 Snapshot(快照)。 |
vm isolate | 同一個進程里可以有很多 isolate,但兩個 isolate 的堆區是不能共享的,所以官方設計了 VM isolate,也就是 kDartVmSnapshot,用來多個 isolate 之間的交互。 |
4.2 業務代碼的加載分析(運行時)
按照 4.1 的分析思路,我們首先需要了解 Flutter 運行時代碼加載的完整流程,經過梳理分析流程如下:
1 )Android- APP 業務代碼的加載流程:
2)IOS- APP 業務代碼的加載流程:
4.3 業務代碼的編譯生成(編譯時)
根據以上的分析,我們知道了 Flutter 業務代碼的數據結構,也知道了在運行時如何加載,因此我們只需要在編譯時做更改,產生自己需要的代碼段,和數據段文件。在運行時加載自己的構建產物即可達到目標。
1)在此以 IOS 構建自己的業務代碼流程做詳細分析:
** 有完成構建流程可以分析,基本流程是 “Dart Code(業務代碼)” -> (通過 Dart 編譯器 gen_snapshot.cc) 生成 snapshot_assemble.S 的匯編文件 -> (通過 xcrun 工具) 生成 snapshot_assemble.o 的 obj 文件 -> (通過 xcun clang 工具鏈) 生成了 App.Framework。
2)Android 的產物構建流程和 IOS 類似。由于 Android 有其他更簡單的方案, 因此省略詳細的構建流程分析,大致如下:
4.4 實現熱更新的方案探索
根據上面的技術分析結果,已經可以獨立生成自己的代碼段,數據段文件。通過需改虛擬機底層代碼的方式,也可以動態的加載運行。但由于 IOS 系統目前底層的系統還不能動態加載可讀寫的代碼段數據到內存中,所以還有技術難點需要突破。但 Android 端有更簡單的路徑可以解決,因此下面以 Android 端為例重點分析思路,大致如下圖所示:
由上圖可以得知,Android 端 熱修復核心步驟如下:
1, 修改 Flutter Engine 代碼,加載指定路徑的 libapp.so 和 flutter_aasets,比如私有目錄 (data/data/files);
2, 編譯 APK 時,利用 Gradle Transform 插件,根據 Flutter SDK 的 engine version 動態替換官方的 Flutter engine,最終寫入修改后的 engine 到 APK;
3, 生成補丁包:利用 BSdiff 算法比較新舊 APK 文件,生成 patch 補丁包
4, APP 啟動時訪問后端接口,根據參數(app 的版本號,補丁包版本號,md5,flutter SDK 版本號,Engine 版本號)拉取補丁包;
5, 合成補丁包:校驗 md5,app 版本號,補丁版本號,安裝時間;
6, 自定義 Flutter Engine 加載指定路徑的 libapp.so 和 flutter_assets 資源文件;
-
Android
+關注
關注
12文章
3936瀏覽量
127403 -
開源
+關注
關注
3文章
3349瀏覽量
42499 -
iOS
+關注
關注
8文章
3395瀏覽量
150607 -
BUG
+關注
關注
0文章
155瀏覽量
15669 -
flutter
+關注
關注
0文章
13瀏覽量
441
原文標題:Flutter熱更新技術探索
文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論