Android原生項(xiàng)目集成Flutter解決方案
了解一下如何在 Android 原生項(xiàng)目中集成 Flutter
生成配置
在原生項(xiàng)目根目錄執(zhí)行命令 flutter create -t module --org {package_name} {module_name} // 此處 module_name 的命令遵循 Android 子 module 的命名即可。不能有中劃線。 // 比如, flutter create -t module --org com.engineer.mini.flutter flutter_sub // 此處 module_name 的命令遵循 Android 子 module 的命名即可。不能有中劃線。 // 比如, flutter create -t module --org com.engineer.mini.flutter flutter_sub </pre>
結(jié)果
Creating project sub_flutter...
sub_flutter/test/widget_test.dart (created)
sub_flutter/sub_flutter.iml (created)
sub_flutter/.gitignore (created)
sub_flutter/.metadata (created)
sub_flutter/pubspec.yaml (created)
sub_flutter/README.md (created)
sub_flutter/lib/main.dart (created)
sub_flutter/sub_flutter_android.iml (created)
sub_flutter/.idea/libraries/Dart_SDK.xml (created)
sub_flutter/.idea/modules.xml (created)
sub_flutter/.idea/workspace.xml (created)
Running "flutter pub get" in sub_flutter... 1,054ms
Wrote 11 files.
最終生成了以上文件,注意這里最后 自動(dòng)執(zhí)行了 flutter pub get 的命令。關(guān)于 flutter pub get 具體做了什么,可以參考后面的。
這里在項(xiàng)目根目錄創(chuàng)建子 module 只是為了把代碼放在一個(gè)倉(cāng)庫(kù),方便維護(hù),理論上可以放在硬盤的任何位置。
配置原生項(xiàng)目 settings.gradle
在配置 settings.gradle 之前先來(lái)簡(jiǎn)單回顧一下關(guān)于 Gradle 的一些基礎(chǔ)知識(shí)。
如果你了解過(guò) Gradle 相關(guān)的配置的話,一定會(huì)看到一個(gè)概念,就是 約定優(yōu)于配置 ,什么意思呢,按照面向?qū)ο蟮乃悸穪?lái)理解,每一個(gè)工程是一個(gè)巨大的 Project 類,整個(gè)類里有很多的屬性。而我們創(chuàng)建的每一個(gè)項(xiàng)目其實(shí)就是一個(gè)具體的 Project 對(duì)象(也就是實(shí)例).約定優(yōu)于配置的意思,就是在 project 實(shí)例化的時(shí)候,其內(nèi)部的屬性已經(jīng)有了默認(rèn)值。那么我們?cè)趺粗烙心男┠J(rèn)值呢?在項(xiàng)目根目錄執(zhí)行
./gradlew properties
就可以得到整個(gè) Project 的一些默認(rèn)配置,比如(此處節(jié)選部分結(jié)果)
------------------------------------------------------------ Root project ------------------------------------------------------------ allprojects: [root project 'MiniApp', project ':app', project ':thirdlib'] android.agp.version.check.performed: true android.enableJetifier: true android.enableR8: true android.enableR8.libraries: true android.useAndroidX: true buildDir: /Users/username/Documents/mygithub/MinApp/build buildFile: /Users/username/Documents/mygithub/MinApp/build.gradle projectDir: /Users/username/Documents/mygithub/MinApp rootDir: /Users/username/Documents/mygithub/MinApp rootProject: root project 'MiniApp'
這里當(dāng)前有一些是我們配置的,比如 useAndroidX,但也有一些是約定的,比如 對(duì)于整個(gè) project 來(lái)說(shuō) buildDir 就是項(xiàng)目根目錄的 build 文件夾等。
執(zhí)行
./gradlew :app:properties
節(jié)選部分結(jié)果
buildDir: /Users/username/Documents/mygithub/MinApp/app/build buildFile: /Users/username/Documents/mygithub/MinApp/app/build.gradle
就會(huì)得到關(guān)于 app 整個(gè) module 現(xiàn)階段的一些配置信息,當(dāng)然這些配置信息除了約定的,還有你自己配置的,比如 buildToolsVersion ,簽名等相關(guān)信息??梢钥吹?buildDir 和整個(gè) project 的是不一樣的。
回到主題, 看看如何把我們剛才創(chuàng)建的 sub_flutter 模塊集成到項(xiàng)目中。(嚴(yán)格來(lái)說(shuō)并不是集成 sub_flutter 模塊,因?yàn)樗皇且粋€(gè) flutter 的模塊,而在 Android 主項(xiàng)目只能集成子 Android module,那么具體改怎么做呢,下面就來(lái)看看其中的奧秘)
按照官方的操作方法,會(huì)要求我們添加以下配置到 settings.gradle 中。
// Include the host app project. include ':app' // assumed existing content setBinding(new Binding([gradle: this])) // new evaluate(new File( // new settingsDir.parentFile, // new 'my_flutter/.android/include_flutter.groovy' // new )) // new
首先看看 這里的 settingsDir 的值。在 settings.gradle 中直接添加
println "settings.dir=" + settingsDir println "settings.dir.parent=" + settingsDir.parent
sync 之后就會(huì)看到輸出
settings.dir=/Users/username/Documents/mygithub/MinApp settings.dir.parent=/Users/username/Documents/mygithub
所以,上面的配置信息,就是說(shuō)結(jié)合 settings 所在目錄的父目錄和我們配置的目錄結(jié)合,找到一個(gè)名為 include_flutter.groovy 的文件,然后去執(zhí)行他。
前面說(shuō)了,創(chuàng)建子 module 的時(shí)候,可以是在項(xiàng)目根目錄,也可以是在其他位置,如果是在其他位置,這里的 my_flutter 可以替換為你創(chuàng)建目錄的絕對(duì)路勁。
這里是在根目錄直接創(chuàng)建的,那么以上的配置就可以簡(jiǎn)化為
setBinding(new Binding([gradle: this])) evaluate(new File(settingsDir, 'sub_flutter/.android/include_flutter.groovy')) include ':sub_flutter' #### 關(guān)于 include_flutter.groovy
上面說(shuō)了,settings.gradle 的配置,其實(shí)就是去執(zhí)行 include_flutter.groovy 這個(gè)文件,可以簡(jiǎn)單看一下這個(gè)文件
def scriptFile = getClass().protectionDomain.codeSource.location.toURI() def flutterProjectRoot = new File(scriptFile).parentFile.parentFile gradle.include ":flutter" gradle.project(":flutter").projectDir = new File(flutterProjectRoot, ".android/Flutter") def localPropertiesFile = new File(flutterProjectRoot, ".android/local.properties") def properties = new Properties() assert localPropertiesFile.exists(), ":exclamation:️The Flutter module doesn't have a `$localPropertiesFile` file." + "\nYou must run `flutter pub get` in `$flutterProjectRoot`." localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } def flutterSdkPath = properties.getProperty("flutter.sdk") assert flutterSdkPath != null, "flutter.sdk not set in local.properties" gradle.apply from: "$flutterSdkPath/packages/flutter_tools/gradle/module_plugin_loader.gradle"
.android 其實(shí)就是一個(gè) Android 項(xiàng)目,他包含一個(gè) Flutter 文件夾,這 Flutter 是一個(gè) library 類型的 Android module ,這個(gè)一點(diǎn)從他的 build.gradle 文件就可以看出。 include_flutter.groovy 所做的事情,就是將當(dāng)前 library 命名為 flutter 的一個(gè) moudle。然后檢查項(xiàng)目中 local.properties 中 sdk 的相關(guān)配置,最后去執(zhí)行 FlutterSDK 的中 gradle 腳本,這里具體的分析就不再展開了。
也就是說(shuō),現(xiàn)在有一個(gè)名為 flutter 的 Android Library Module 。這個(gè) module 包含 flutter 的所有配置。我們?nèi)绻蕾嚵诉@個(gè) module ,那么就相當(dāng)于是依賴了 Flutter .
依賴 flutter
最后在原生項(xiàng)目的 application-module 的 build.gradle 的 dependencies 閉包中添加
implementation project(':flutter')
至此,原生項(xiàng)目已經(jīng)有了 Flutter 的依賴,可以使用 Flutter 的 View 了。
至此,現(xiàn)在的原生項(xiàng)目就包含 Flutter SDK 的所有依賴了,UI 相關(guān)的內(nèi)容,改怎么寫還是用 dart 在 main.dart 中寫,然后我們就可以把這個(gè) dart 渲染出來(lái)的內(nèi)容按照 Activity 、Fragment 或 View 的形式添加到已有的項(xiàng)目中了。
flutter pub get
flutter pub get 或者 pub get 是在做 flutter 的時(shí)候在使用第三方 lib 或版本更新的時(shí)候經(jīng)常會(huì)使用一個(gè)命令,通過(guò)這個(gè)命令會(huì)拉取相關(guān)的依賴,其實(shí)這個(gè)命令還會(huì)自動(dòng)生成 Android 和 iOS 的原生項(xiàng)目。比如在我們創(chuàng)建就的 sub_flutter 模塊中,均自動(dòng)生成了 .android 和 .ios 的原生項(xiàng)目目錄。同時(shí)這兩個(gè)目錄都是點(diǎn)打頭的,那么一般情況下就是隱藏文件,同時(shí)通過(guò) .gitignore 文件也可以看到,對(duì)于 flutter module 形式來(lái)說(shuō),這兩個(gè)文件夾都是被忽略的,畢竟 flutter module 的核心,還是為了方便以 module 的形式集成到原生的項(xiàng)目中,內(nèi)部的兩個(gè)原生目錄,一方面是為了方便集成,另一方面是便于直接運(yùn)行執(zhí)行 hot-reload 的調(diào)試。
以上就是Android原生項(xiàng)目集成Flutter解決方案的詳細(xì)內(nèi)容,更多關(guān)于Android集成Flutter的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Flutter中顯示條件Widget的實(shí)現(xiàn)方式
在 Flutter 日常開發(fā)中經(jīng)常會(huì)遇見這樣的需求,如: 只有用戶是 VIP 時(shí),才能展示某個(gè)入口或者某個(gè)模塊,這樣的需求在開發(fā)業(yè)務(wù)需求中多如牛毛,那你是如何來(lái)優(yōu)雅的實(shí)現(xiàn)的呢,本文將給大家介紹Flutter中顯示條件Widget的實(shí)現(xiàn)方式,需要的朋友可以參考下2024-04-04Android顯式啟動(dòng)與隱式啟動(dòng)Activity的區(qū)別介紹
為什么要寫顯式啟動(dòng)與隱式啟動(dòng)Activity,Android的Acitivity啟動(dòng)大致有兩種方式:顯式啟動(dòng)與隱式啟動(dòng),下面分別介紹2014-09-09Kotlin?Dispatchers協(xié)程調(diào)度器源碼深入分析
Kotlin協(xié)程不是什么空中閣樓,Kotlin源代碼會(huì)被編譯成class字節(jié)碼文件,最終會(huì)運(yùn)行到虛擬機(jī)中。所以從本質(zhì)上講,Kotlin和Java是類似的,都是可以編譯產(chǎn)生class的語(yǔ)言,但最終還是會(huì)受到虛擬機(jī)的限制,它們的代碼最終會(huì)在虛擬機(jī)上的某個(gè)線程上被執(zhí)行2022-11-11Android使用TextView實(shí)現(xiàn)無(wú)下劃線超鏈接的方法
這篇文章主要介紹了Android使用TextView實(shí)現(xiàn)無(wú)下劃線超鏈接的方法,結(jié)合實(shí)例形式分析了Android中TextView超鏈接去除下劃線的相關(guān)實(shí)現(xiàn)技巧與注意事項(xiàng),需要的朋友可以參考下2016-08-08Android實(shí)現(xiàn)下載工具的簡(jiǎn)單代碼
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)下載工具的簡(jiǎn)單代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03Android 下載并打開PDF,Doc,Dwg文檔實(shí)例
本篇文章主要介紹了Android 下載并打開PDF,Doc,Dwg文檔實(shí)例,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-04-04Android Studio使用教程(四):Gradle基礎(chǔ)
這篇文章主要介紹了Android Studio使用教程(四):Gradle基礎(chǔ),本文講解了什么是Gradle、安裝Gradle、Gradle 基本概念等內(nèi)容,需要的朋友可以參考下2015-05-05Android開發(fā)之串口編程原理和實(shí)現(xiàn)方式
提到串口編程,就不得不提到JNI,不得不提到JavaAPI中的文件描述符類:FileDescriptor;下面我分別對(duì)JNI、FileDescriptor以及串口的一些知識(shí)點(diǎn)和實(shí)現(xiàn)的源碼進(jìn)行分析說(shuō)明,感興趣的朋友可以了解下2013-01-01