本篇將帶你深刻了解 Flutter 中打包和插件安裝等原理,幫你快速完成 Flutter 集成到現有 Android 項目,實現混合開發支持。java
前文:react
隨着各類跨平臺框架的不斷涌現,不少時候咱們會選擇混合開發模式做爲腳手架 ,由於企業通常不會把業務都壓在一個框架上,同時除非是全新項目,否則出於對原有業務重構的 成本和風險 考慮,都會選擇混合開發去嘗試入坑。android
可是混合開發會對 打包、構建和啓動等流程熟悉度要求較高 ,同時遇到的問題也更多,之前我在 React Native
也寫過相似的文章 :《從Android到React Native開發(4、打包流程解析和發佈爲Maven庫)》 ,而這方面是有不少經驗能夠通用的,因此適當的混開模式有利於避免一些問題,同時只有瞭解 Flutter
總體項目的構建思路,纔有可能更溫馨的躺坑。git
額外嘮叨一句,跨平臺的意義更多在於解決多端邏輯的統一 ,至少避免了邏輯重複實現,因此企業剛開始,通常會選擇一些輕量級業務進行嘗試。github
官方將來將有
Flutter build aar
的方法可提供使用。
通常跨平臺混合開發會有兩種選擇:web
Flutter
總體框架依賴和打包腳本都集成到主項目中。aar
的完整庫集成形式添加到主項目。兩種實現方法各有利弊:npm
第一種方式能夠更方便運行時修改問題,可是對主項目「污染」會比較高,同時改動會大一些。react-native
第二種方式 須要單獨調試後,更新 aar
文件再集成到項目中調試,可是這類集成方式更乾淨,同時 Flutter
相關代碼可獨立運行測試,且改動較小。緩存
通常而言,對於普通項目我是建議以 第二種方式集成到項目中的 ,經過新建一個 Flutter
工程,而後對工程進行組件化腳本處理,讓它 既能以 apk形式單獨運行調試,又能打包爲aar形式對外提供支持。app
相信對於原平生臺熟悉的應該知道,咱們能夠經過簡單修改項目gradle
腳本,讓它快速支持這個能力,以下圖片所示,圖片中爲省略的部分腳本代碼,完整版可見 flutter_app_lib 。
咱們經過了 isLib
標記爲去簡單實現了項目的打包判斷,當項目做爲 lib
發佈時,設置 isLib
爲 true,以後執行 ./gradlew assembleRelease
便可 ,剩下的工做依舊是 Flutter
自身的打包流程,而對於打包後的 aar
文件直接在原生項目裏引入便可完成依賴。
而通常接入時,若是須要 token
、用戶數據等信息,推薦提供定義好原生接口,如 init(String token, String userInfo)
等,而後經過MethodChannel
將信息同步到 Flutter
中。
對於原生主工程,只須要接入 aar
文件,完成初始化並打開頁面,而無需關心其內部實現,和引入普通依賴並沒有區別。
你可能須要修改的還有
AndroidManifset
中的啓動MainActivity
移除,而後添加一個自定義Activity
去繼承FlutterActivity
完成自定義。
若是普通狀況下,到上面就能夠完成 Flutter
的集成工做了,可是每每事與願違,一些 Flutter
插件在提供功能時,每每是經過原生層代碼實現的,如 flutter_webview
、android_intent
、device_info
等等,那這些代碼是怎麼被引用的呢?
這裏稍微提一下,用過
React Native
的應該知道,帶有原生代碼的React Native
插件,在npm
安裝之後,須要經過react-native link
命令完成安裝處理。 這個命令會觸發腳本修改原生代碼,從而修改gradle
腳本增長對插件項目的引用,同時修改java
代碼實現插件的模版引入,這使得項目在必定程度被插件「污染」。
在 React Native
中帶有原生代碼的插件,會被以本地 Module
工程的方式引入,那 Flutter
呢?
其實原理上 Flutter
帶有原生代碼的插件,在插件安裝後,也是會以本地 Module Project
的形式引入 ,可是它整個過程更加巧妙,讓開發中對這個過程幾乎無感。
以下圖所示,不知道你注意過沒有,在插件安裝以後,全部帶原生代碼的插件,都會以路徑和插件名的key=value
形式 存在 .flutter-plugins
文件中。
而在 android
工程的 settings.gradle
裏,以下圖所示,會經過讀取該文件將 .flutter-plugins
文件中的項目一個個 include
到主工程裏。
以後就是主工程裏的 apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
腳本的引入了,這個腳本通常在於 flutterSDK/packages/flutter_tools/gradle/
目錄下,以下代碼所示,其中最關鍵的部分一樣是 讀取 .flutter-plugins
文件中的項目,而後一個一個再 implementation
到主工程裏完成依賴。
自此全部原生代碼的 Flutter
插件,都被做爲本地 Module Project
的形式引入主工程了 ,最後腳本會自動生成一個 GeneratedPluginRegistrant.java
文件,實現原生代碼的引用註冊, 而這個過程對你徹底是無感的。
說了那麼多就是爲了說明,既然插件是被看成本地 Module Project
的形式引入,那麼這時候按照原來直接打包 aar 是會有問題的:
`Android` 默認 `gradle` 腳本打包時,對於 `project` 和遠程依賴只會打包引用而不會打包源碼和資源。
因此這時候就須要 fat-aar
的加持了,關於 fat-aar
的詳細概念可見 :《從Android到React Native開發(4、打包流程解析和發佈爲Maven庫)》 ,這裏能夠簡單理解爲,這是一個支持將引用代碼和資源到合併到一個 aar 的插件。
以下代碼所示,咱們在本來的組件化腳本上,經過增長 apply plugin: 'com.kezong.fat-aar'
引入插件,而後參考 Flutter
腳本對 .flutter-plugins
文件中的項目進行 embed
依賴引用便可 ,這時候再打包出的 aar
文件即爲完整 Flutter
項目代碼。
完整版可見 flutter_app_lib 。
最後須要說的問題就是堆棧了。
若是說混合開發中最難處理的是什麼,那必定是各平臺之間的堆棧管理,通常狀況下咱們都會避免混合堆棧的相互調用 ,可是面對不得不如此爲之的狀況下,閒魚給出了他們的答案:fluttet_boost
。
咱們知道 Flutter
整個項目都是繪製在一個 Surface
畫布上,而fluttet_boost
將堆棧統一到了原生層,經過一個單例的 flutter engine
進行繪製。
每一個 FlutterFragment
和 FlutterActivity
都是一個 Surface
承載容器,切換頁面時就是切換 Surface
渲染顯示,而對於不渲染的頁面經過 Surface
截圖緩存畫面顯示。
這樣整個 Flutter
的路由就被映射到原生堆棧中,統一由原生頁面堆棧管理,Flutter
內每 push
一個頁面就是打開一個 Activity
。
flutter_boost
截止到我測試的時間 2019-05-16, 只支持 1.2以前的版本。flutter_boost
的總體流程相對複雜,同時對於Dialog
的支持並很差,且業務跳轉深度太深時會出現黑屏問題。
自此,第十四篇終於結束了!(///▽///)