1. 程式人生 > >Flutter 混合工程改造實踐

Flutter 混合工程改造實踐

背景

由於原有的 iOS 和 Android 工程都已相當龐大,如何將 Flutter 無縫橋接到這些大工程並保證開發效率不受影響成為優先要解決的問題。

本文針對專案實踐人員給出了一種通用的工程改造方案,希望為準備轉型 Flutter 的團隊提供參考。

問題

Flutter 的工程結構比較特殊,由 Flutter 目錄再分別包含 Native 工程的目錄(即 iOS 和 Android 兩個目錄)組成。預設情況下,引入了 Flutter 的 Native 工程無法脫離父目錄進行獨立構建和執行,因為它會反向依賴於 Flutter 相關的庫和資源。 在這裡插入圖片描述

很顯然,在擁有了 Native 工程的情況下,開發者不太可能去建立一個全新的 Flutter 工程重寫整個產品,因此 Flutter 工程將包含已有的 Native 工程,這樣就帶來了一系列問題:

1)構建打包問題

引入 Flutter 後,Native 工程因對其有了依賴和耦合,從而無法獨立編譯構建。在 Flutter 環境下,工程的構建是從 Flutter 的構建命令開始,執行過程中包含了 Native 工程的構建,開發者要配置完整的 Flutter 執行環境才能走通整個流程;

2)混合編譯帶來的開發效率的降低

在轉型 Flutter 的過程中必然有許多業務仍使用 Native 進行開發,工程結構的改動會使開發無法在純 Native 環境下進行,而適配到 Flutter 工程結構對純 Native 開發來說又會造成不必要的構建步驟,造成開發效率的降低。

目標

針對以上問題,我們提出了以下的改造目標,力求最小化 Native 工程對 Flutter 相關檔案的依賴,使得:

1)Native 工程可以獨立地編譯構建和除錯執行,進而最大限度地減少對相關開發同學的干擾並使打包平臺不再依賴 Flutter 環境及相關流程;

2)Native 工程處在 Flutter 環境中時(即作為 iOS 或 Android 子目錄)能夠正確依賴相關庫和檔案,正常執行各類 Flutter 功能,如 dart 程式碼的構建,除錯,hot reload 等,保證 Flutter 環境下開發的正確性。

方案的制定

兩種模式

首先定義 Native 工程處於獨立目錄環境下稱為 Standalone 模式,處於 Flutter 目錄下稱為 Flutter 模式。目標中純 Native 開發或平臺打包就處於 Standalone 模式,Flutter 對開發人員和打包平臺來說是透明的存在,不會影響構建與除錯;而 Flutter 的程式碼則在 Flutter 模式進行開發,其相關庫的生成,編譯和除錯都走 Flutter 定義的流程。 在這裡插入圖片描述

理清依賴

從上面的定義來看,改造的核心就是把 Standalone 模式提取出來,那麼就要理清 Standalone 模式對 Flutter 的依賴,並將其提取成第三方的庫,資源或原始碼檔案。以 iOS 為例,通過閱讀 Flutter 構建的原始碼,可知 Xcode 工程對 Flutter 有如下依賴:

1)App.framework:dart 業務原始碼相關檔案; 2)Flutter.framework:Flutter 引擎庫檔案; 3)pubs 外掛目錄及用於索引的檔案:Flutter 下的外掛,包括各種系統的和自定義的 channels; 4)flutter_assets:Flutter 依賴的靜態資源,如字型,圖片等;

依賴引入的策略

改造過程中閒魚嘗試過兩種依賴引入策略,以下分別進行闡述。

1)本地依賴

通過修改 Flutter 構建流程將其庫檔案,原始碼和資源直接放置到 Native 工程的子目錄中進行引用,以 iOS 為例,就是將 Flutter.framework 及相關外掛等做成本地的 pod 依賴,資源也複製到本地進行維護。 由此,Standalone 模式便具備了獨立構建和執行的能力,對於純 Native 開發人員來說 Flutter 只是一些二方庫與資源的合集,無需關注。 而在 Flutter 模式下,dart 原始碼的構建流程不變,不影響編譯和除錯;同時由於是本地依賴,Flutter 模式下的各種改動也實時可以同步到 Native 工程的子目錄中,提交修改後 Standalone 模式也就擁有了最新的 Flutter 相關功能。

  • 優點:Flutter 相關內容的改動同步到 Standalone 模式也比較方便;
  • 缺點:需要對 Flutter 原有的構造流程進行稍嫌複雜的改動,並且與後續的 Flutter 程式碼合併會有衝突,且 Native 工程與 Flutter 的內容還是耦合在本地不夠獨立。

2)遠端依賴

遠端依賴的想法是將 Flutter 所有依賴內容都放在獨立的遠端倉庫中,在 Standalone 模式下引用遠端倉庫中的相關資源,原始碼和庫檔案,Flutter 模式下的構建流程和引用方式則不變。

  • 優點:對 Flutter 自身的構建流程改動較少並且較徹底第解決了本地耦合的問題;
  • 缺點:同步的流程變得更繁瑣,Flutter 內容的變動需要先同步到遠端倉庫再同步到 Standalone模式方能生效。

PS. 閒魚最終選擇了這個策略。 在這裡插入圖片描述

改造的實現

目錄的組織

Flutter 模式下父工程目錄下的 ios 和 android 的子目錄分別包含對應的 Native 工程,程式碼管理上子工程可以使用 git 的 submodule 形式,保證目錄間的獨立。

遠端依賴的實現

在 Standalone 模式下,Flutter 的依賴內容都指向遠端倉庫中的對應檔案,而在 Flutter 模式下依賴的方式不變。

1)向 Standalone 模式同步 Flutter 的變更

由於遠端依賴的問題是同步變動比較麻煩,為此閒魚開發了一系列指令碼工具使該過程儘量自動完成。 假設 Flutter 的內容(可能是業務原始碼,引擎庫或某些資原始檔)發生變化,那麼在 Flutter 模式下構建結束後,指令碼會提取生成好的所有依賴檔案拷貝到遠端倉庫,提交併打 tag,然後依據打出的 tag 生成新的遠端依賴說明(比如 iOS 下的 podspec),最後在 Standalone 模式下修改 Flutter 的依賴至最新的版本,從而完成整個同步過程。 在這裡插入圖片描述

2)同步的時機

建議在提測及灰度期間,每次 Flutter 業務的提交都能夠觸發同步指令碼的執行和 app 打包;開發期間保持每日一次的同步即可。

總結

為解決引入 Flutter 後的工程適配問題,我們抽取了 Flutter 的相關依賴放到遠端供純 Native 工程進行引用,從而保證了 Flutter 與純 Native 開發的相互獨立與並行執行。

相信該方案也可以為轉型 Flutter 的團隊提供幫助,當然專案間的差異也會導致方案的不同,因此如有更好的方法和意見也期望多多交流!