Flutter 2.2.X 版本熱修復實現思路分享(Android+Flutter混開專案)

悟篤篤發表於2021-07-17

已經好久沒有寫文章了,最近被業務折磨的一塌糊塗,跟個陀螺似的,被逆時針、順時針來回地抽/(ㄒoㄒ)/。
好久前就想捋一捋 Flutter 混開專案中熱修復的實現方式,最近在業餘時間耗費了一些精力終於實現了該功能,故在此分享下實現思路。
cry.jfif


當前文章中的 FlutterSDK 特指 2.2.2 版本,新版本 SDK 中涉及熱修復視窗的相關程式碼發現了變化,1.X 版本的實現方式已經過時了。

實現原理

我的實現思路用到 Tinker + ASM + 自定義GradlePlugin ,Tinker 用於打資源差分包,ASM 用於編輯關鍵類的位元組碼,GradlePlugin 中使用 Transform 在 Android 專案編譯期間去使用 ASM 的位元組碼編輯功能。

在 Flutter 的早期版本中,Google 是有提供官方的熱修復能力的,但是在後期的迭代版本中又將該能力給遮蔽掉了。但是其仍然留有一個視窗給到我們去對 Flutter 程式碼與資源進行熱修復(特指Android+Flutter混開專案),只要瞭解了該視窗的具體發生時機Flutter Module 構建產物 的知識,我們便可以很直觀地實現 Flutter 的熱修復功能。

  • Flutter 構建產物(release):我們只需要關注第2與3點

    1. libflutter.so:Flutter 引擎相關程式碼,不需要關心。
    2. libapp.so:Flutter Module 會編譯成該 動態庫,我們編寫的 dart 程式碼都在這裡,熱修復 Flutter 程式碼通過替換該動態庫實現。
    3. assets/flutter/xxx:Flutter Module 的資源位於 apk 包的 assets 下。
  • 熱修復視窗:貼程式碼可能要貼很多程式碼,我這裡簡單描述下該該視窗的發生時機

    1. FlutterActivity 中的委託類 FlutterActivityDelegateonCreate 函式中,會執行 Flutter 引擎的初始化方法。

    2. 初始化方法會通過下述呼叫程式碼:

     String[] args = getArgsFromIntent(activity.getIntent());
     FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args);
    複製程式碼

    我們關注重點在 FlutterMain.ensureInitializationComplete() 中。

    1. 具體實現程式碼就不展開,FlutterMain.ensureInitializationComplete() 中會有 libapp.so 動態庫的位置引數的配置與傳遞,它最終的是通過 FlutterJNI.init(xxx) 函式進行初始化(注意:libapp.so 動態庫的載入與平時的 loadLibrary(String libname) 機制不同,不能簡單的使用 Tinker 進行熱修復)。
    2. FlutterJNI.init(xxx) 函式的入參 String[] args 會包含2個帶有 --aot-shared-library-name= 的字串元素用於指定 libapp.so 動態庫的位置,其中一個是相對位置,一個是絕對位置。相對位置定址失敗便會使用絕對位置進行定址。
    3. 我們只需要使用 ASM + GradlePlugin 編輯FlutterJNI.init(xxx) 函式的位元組碼,將 --aot-shared-library-name= 字串元素指定為我們自定義的動態庫絕對路徑即可實現 Flutter 程式碼的熱修復。

實現步驟

如下

  1. 引入 Tinker 熱修復能力,這個沒啥好說的吧

  2. 對 Flutter 資源和程式碼進行修改,方便驗證。

  3. 開發 Gradle 外掛,使用 Transform api + ASM ,對 FlutterJNI.init(xxx) 的函式位元組碼進行編輯。

  4. FlutterJNI.init(xxx) 的函式位元組碼編輯的主要做以下操作

    1. 判斷當前應用是否有做 Tinker 熱修復,該次熱修復操作是否有下發 libapp.so 動態庫。

    2. 獲取 libapp.so 動態庫的絕對地址,修改字串陣列中 --aot-shared-library-name= 的字串元素的值指向該絕對地址。

    3. 實現 Flutter 程式碼熱修復,而 Flutter 資源熱修復不需關心,Tinker 本身支援 assets 的熱修復,不需要額外處理。

    4. 該步驟還可以優化,外掛的開啟時機建議在只做 Flutter 熱修復的時候才開啟。

    5. 使用 Gradle 外掛,執行 Tinker patch 生成的 Task,安裝補丁重啟驗證。

按照以上步驟,本人親測可實現 Flutter 的熱修復功能(Android+Flutter混開專案)。

小結

因精力有限,文章中很多內容沒有展開描述,如有錯誤還望指出,共同進步哈。

如果你覺得本篇文章有用的話還請點贊支援下,謝謝!

相關文章