Android工程內嵌Flutter


本文記錄一下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項目,無需依賴任何原生的調用,自身即可啟動調試。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM