本文記錄一下Android主工程中嵌入部分Fluttter頁面的實現方法。
創建一個Android工程模擬你的現有工程
為了讓Android工程和Flutter工程互不干擾,這里不再以Android工程為工程的跟目錄,而是讓Android工程和平級的Flutter工程的公共目錄作為根目錄。 最終的目錄結構應該是下面這樣的
你的項目根目錄(隨便什么你喜歡的地方)
├── 原生安卓工程(FlutterInAndroid)
└── Flutter工程 (my_flutter)
所以首先在你的項目根目錄
下用AS創建一個新的Android原生項目,可以勾選上kotlin支持,這樣更舒服。 創建完成后你會得到一個這樣的結構
你的項目根目錄(隨便什么你喜歡的地方)
└── FlutterInAndroid
FlutterInAndroid目錄內是一個完整的Android工程
module模式創建Flutter工程
接下來使用Flutter命令來創建module工程,在你的項目根目錄
下執行:
flutter create -t module my_flutter
創建完成后你會得到一個這樣的結構
你的項目根目錄(隨便什么你喜歡的地方)
├── FlutterInAndroid
└── my_flutter
my_flutter是一個Flutter的module工程,用來供Android項目引入
在Android工程中引入依賴
在FlutterInAndroid這個Android工程的setting.gradle文件中追加flutter工程的引入
你的項目跟目錄/FlutterInAndroid/setting.gradle
include ':app' //加入下面配置 setBinding(new Binding([gradle: this])) evaluate(new File( settingsDir.parentFile, 'my_flutter/.android/include_flutter.groovy' ))
在app的build.gradle文件中加入工程依賴
你的項目跟目錄/FlutterInAndroid/app/build.gradle
... dependencies { ... // 加入下面配置 implementation project(':flutter') }
使用AS打開FlutterInAndroid工程,重新構建項目,即可成功的將Flutter加入Android工程。
在Android工程中創建Flutter的View
Flutter提供了兩種方式讓Android工程來引用組件,一種是View,一種是Fragment,這里選用View來進行講解,Fragment同理。 這里我們用兩種方式來引入FLutter,本質是還是是作為一個view引入布局還是將FlutterView作為Activity的根View。
以單個view引入布局
val flutterView = Flutter.createView(this,lifecycle,"route1")
通過上面很簡單的一個方法,我們就能通過Flutter創建出一個view,這個方法提供三個參數,第一個是Activity,第二個參數是一個Lifecycle對象,我們之間取Activity的lifecycle即可,第三個參數是告訴Flutter我們要創建一個什么樣的view,這個字符串參數可以在Flutter工程中獲取得到。
創建出這個FlutterView之后就可以按常規的操作來將它加入到任何你想要的布局中去了。
以根view作為Activity
創建一個空的Activity,用Flutter創建一個View作為頁面的根View:
class FlutterActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_flutter) val flutterView = Flutter.createView(this@FlutterActivity,lifecycle,"route1") val layout = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) addContentView(flutterView, layout) } }
這里我們並沒有使用setContentView而是是用了addContentView這個方法,原因是這樣的:
雖然FLutter的加載速度非常快,但是這個過程依然存在,在創建FLutterView之前我們先給ContentView設置了一個R.layout.activity_flutter布局,這個布局可以作為FlutterView加載完成之前展示給用戶的界面,當然大部分情況下用戶根本感知不到這個界面Flutter已經加載完成了,但我們仍需要它,因為debug模式下造成Flutter的加載速度並不是非常快,這個界面可以給開發人員看,還有就是如果沒有這個界面的話在Activity的加載過程會出現一個黑色的閃屏,而這個情況對用戶來說並不友好。
在Flutter工程中根據不同的route創建不同的組件
用AndroidStudio在你的項目跟目錄/my_flutter
打開Flutter工程,這時候AndroidStudio插件會識別到Flutter工程並以Flutter工程進行加載。
忽略掉.android和.ios文件夾之后你會發現,這個FLutter工程和完整的Flutter工程並沒有任何不同,你依然能夠以完整Flutter工程的流程來進行Flutter開發並啟動調試,這是一個非常人性化的設計。
上面我們在原生Android工程中以View的形式調用了Flutter,而Flutter本質上是只有一個入口的,也就是main.dart文件中的main函數:
void main() => runApp(new MyApp());
我們的目的是根據原生工程的調用讓Flutter生成不同的組件作為View來供原生工程使用,那么我們就可以從這個main函數來入手。
通過文檔我們可以通過window
的全局變量中獲取到當前的routeName,這個值正是上面通過原生工程傳給Flutter的標識,有了這個標識就可以簡單的做判斷來進行不同的組件創建了:
import 'dart:ui'; import 'package:flutter/material.dart'; void main() => runApp(_widgetForRoute(window.defaultRouteName));
//根據不同的標識創建不同的組件給原生工程調用
Widget _widgetForRoute(String route) { switch (route) { case 'route1': return SomeWidget(...); case 'route2': return SomeOtherWidget(...); default: return Center( child: Text('Unknown route: $route', textDirection: TextDirection.ltr), ); } }
讓Flutter模塊支持熱加載
首先在Flutter目錄下啟動監聽服務,在你的項目根目錄/my_flutter
下執行
flutter attach
執行后,監聽服務會等待並監聽debug應用中flutter的狀態
然后在打開FlutterInAndroid項目的AS中以正常方式調試運行,在真機或模擬器中運行app后並不會立即出發flutter的監聽服務,當flutter的view或Fragment激活時才會觸發。
當flutter的監聽服務和app建立連接后,終端會出現如下輸出:
$ flutter attach -d W8 Waiting for a connection from Flutter on PLK UL00... Done. Syncing files to device PLK UL00... 8.7s 🔥 To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R". An Observatory debugger and profiler on PLK UL00 is available at: http://127.0.0.1:54218/ For a more detailed help message, press "h". To quit, press "q".
這時我們修改flutter工程中的dart代碼文件,保存后在終端中點擊r
鍵即可進行熱加載,R
鍵進行熱重啟。
簽名打包
引入flutter工程后,對Android原生工程的構建基本上沒有影響,打包按常規操作即可。
Flutter創建的module工程中的Android工程與純Flutter工程的中Android工程的比較
區別 | Flutter的module工程中的Android工程 | 純Flutter工程中的Android工程 |
---|---|---|
文件夾名稱 | .android | android |
包含的module | app和Flutter | app |
說明1 | app只提供了入口Activity,Flutter包含了插件擴展及原生工程調用的接口 | app包含入口Activity及插件擴展 |
說明2 | app供Flutter自身開發調試,Flutter作為module供Android原生調用 | app作為Android工程運行及打包 |
為了方便描述我們稱前者為module工程,后者為完整工程。
由此可見,雖然module工程中提供了名為Flutter的module供原生工程調用,但仍然保留了app工程,這樣非常大程度的方便了flutter工程師來單獨開發flutter項目,無需依賴任何原生的調用,自身即可啟動調試。