上一篇文章我們已經(jīng)了解如何修改flutter engine代碼實(shí)現(xiàn)動(dòng)態(tài)化效果柑贞,這一篇文章主要是講解,flutter build aar的過程,然后修改對(duì)應(yīng)的gradle編譯腳本,目的是打出適合混合工程使用的aar包些阅。
一、flutter build aar打包結(jié)果
這一小節(jié)斑唬,我們先來看下正常使用
flutter build aar
打包出的aar的結(jié)構(gòu)是怎么樣的
1.1市埋、前置條件
Android混合工程,先創(chuàng)建一個(gè)新的Android項(xiàng)目赖钞,然后新建flutter module
腰素,也可以使用flutter create -t module --org com.example flutter_module
創(chuàng)建。
cd flutter_module
雪营,然后執(zhí)行flutter pub get
弓千,會(huì)自動(dòng)創(chuàng)建.android
文件
1.2、執(zhí)行flutter build aar
我們這里只分析release版本的aar献起,將flutter_release-1.0.aar
的后綴修改成jar洋访,然后用反編譯工具JD-GUI打開flutter_release-1.0.jar
,結(jié)果如下:
可以看到打包的代碼中沒有flutter.jar
的代碼谴餐,也沒有libflutter.so
姻政,那么這兩個(gè)文件放在哪兒了呢?
如何將這兩個(gè)文件打包到aar中呢岂嗓?帶著問題我們來看下執(zhí)行flutter build aar
過程中都執(zhí)行了哪些腳本汁展。
這里先提一個(gè)解決方案,那就是fat-aar
來打包aar厌殉,具體使用請大家自行百度
二食绿、flutter build aar的過程解析
關(guān)于flutter命令的執(zhí)行流程,里面的東西還是挺多的公罕,我會(huì)單獨(dú)拿一篇文章來寫器紧,這一小節(jié),主要介紹build過程中涉及到的兩個(gè)gradle文件:
flutter.gradle
楼眷、aar_init_script.gradle
2.1铲汪、flutter.gradle
在:Flutter
的build.gradle中引用了apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
// 引用plugin
apply plugin: FlutterPlugin
// 緊接著是plugin的實(shí)現(xiàn)
class FlutterPlugin implements Plugin<Project> {
void apply(Project project) {
// 創(chuàng)建擴(kuò)展字段source、target
project.extensions.create("flutter", FlutterExtension)
// 其他任務(wù)完成后執(zhí)行addFlutterTasks(設(shè)置flutter相關(guān)初始化項(xiàng))
project.afterEvaluate this.&addFlutterTasks
// abi相關(guān)配置
if (shouldSplitPerAbi())
罐柳。掌腰。。
张吉。辅斟。。
// 獲取engine的版本芦拿,方便從maven上下載
engineVersion = useLocalEngine() ? "+" : "1.0.0-" + Paths.get(flutterRoot.absolutePath, "bin", "internal", "engine.version").toFile().text.trim()
士飒。。蔗崎。
// 使用本地engine時(shí)的配置獲取酵幕,需要在gradle.properties中配置
if (useLocalEngine()) {
// This is required to pass the local engine to flutter build aot.
String engineOutPath = project.property('local-engine-out')
File engineOut = project.file(engineOutPath)
if (!engineOut.isDirectory()) {
throw new GradleException('local-engine-out must point to a local engine build')
}
localEngine = engineOut.name
localEngineSrcPath = engineOut.parentFile.parent
}
// 每種type類型添加dependencies
project.android.buildTypes.each this.&addFlutterDependencies
project.android.buildTypes.whenObjectAdded this.&addFlutterDependencies
}
}
核心的就是這個(gè)apply
方法,主要是配置dependencies
和其他一些相關(guān)配置缓苛,下面我們來看看addFlutterDependencies
方法做了哪些事情:
/**
* Adds the dependencies required by the Flutter project.
* This includes:
* 1. The embedding
* 2. libflutter.so
*/
// 只看這個(gè)注釋就能知道芳撒,這個(gè)方法是用于添加flutter.jar和libflutter.so的
void addFlutterDependencies(buildType) {
String flutterBuildMode = buildModeFor(buildType)
// 只有在使用本地engine時(shí)supportsBuildMode會(huì)判斷gradle.properites中的local-engine-build-mode是否和當(dāng)前flutterBuildMode相同
if (!supportsBuildMode(flutterBuildMode)) {
return
}
// 設(shè)置maven源路徑
String repository = useLocalEngine() ? project.property('local-engine-repo') : MAVEN_REPO
project.rootProject.allprojects {
repositories {
maven {
url repository
}
}
}
// Add the embedding dependency.
// 添加flutter.jar引用
addApiDependencies(project, buildType.name, "io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion")
。未桥。笔刹。
platforms.each { platform ->
String arch = PLATFORM_ARCH_MAP[platform].replace("-", "_")
// 添加libflutter.so依賴
addApiDependencies(project, buildType.name,
"io.flutter:${arch}_$flutterBuildMode:$engineVersion")
}
}
2.2、aar_init_script.gradle
這個(gè)腳本是會(huì)有flutter build aar觸發(fā)的冬耿,文件路徑
$flutterRoot/packages/flutter_tools/gradle/aar_init_script.gradle
projectsEvaluated {
assert rootProject.hasProperty("is-plugin")
if (rootProject.property("is-plugin").toBoolean()) {
assert rootProject.hasProperty("output-dir")
// In plugin projects, the root project is the plugin.
configureProject(rootProject, rootProject.property("output-dir"))
return
}
// 針對(duì)混合工程時(shí)的 `:flutter` module
Project moduleProject = rootProject.subprojects.find { it.name == "flutter" }
assert moduleProject != null
assert moduleProject.hasProperty("output-dir")
configureProject(moduleProject, moduleProject.property("output-dir"))
// 獲取所有的plugin子工程
Set<Project> modulePlugins = rootProject.subprojects.findAll {
it.name != "flutter" && it.name != "app"
}
modulePlugins.each { pluginProject ->
configureProject(pluginProject, moduleProject.property("output-dir"))
moduleProject.android.libraryVariants.all { variant ->
String variantName = variant.name.capitalize()
// 插件的`assembleAar$variantName`任務(wù)執(zhí)行完后再執(zhí)行moduleProject的任務(wù)
moduleProject.tasks.findByPath("assembleAar$variantName")
.dependsOn(pluginProject.tasks.findByPath("assembleAar$variantName"))
}
}
}
上面是入口方法舌菜,從上面的腳本里能看出有一個(gè)核心的方法configureProject
,下面我們來看看這個(gè)方法的作用:
void configureProject(Project project, String outputDir) {
// 保證是Android工程
if (!project.hasProperty("android")) {
throw new GradleException("Android property not found.")
}
// 保證是library而不是application
if (!project.android.hasProperty("libraryVariants")) {
throw new GradleException("Can't generate AAR on a non Android library project.");
}
// 使用maven插件
project.apply plugin: "maven"
project.android.libraryVariants.all { variant ->
// 在上傳maven任務(wù)完成后再執(zhí)行這個(gè)任務(wù)
addAarTask(project, variant)
}
// 上傳的maven路徑亦镶,此處是maven的本地庫的一個(gè)用法
project.version = project.version.replace("-SNAPSHOT", "")
project.uploadArchives {
repositories {
mavenDeployer {
repository(url: "file://${outputDir}/outputs/repo")
}
}
}
if (!project.property("is-plugin").toBoolean()) {
return
}
// build aar目前暫時(shí)不支持使用本地engine
if (project.hasProperty('localEngineOut')) {
throw new GradleException(
"Local engine isn't supported when building the plugins as AAR. " +
"See: https://github.com/flutter/flutter/issues/40866")
}
// 添加倉庫以及依賴
project.repositories {
maven {
url "http://download.flutter.io"
}
}
String engineVersion = Paths.get(getFlutterRoot(project), "bin", "internal", "engine.version").toFile().text.trim()
project.dependencies {
// 添加flutter.jar依賴
compileOnly ("io.flutter:flutter_embedding_release:1.0.0-$engineVersion") {
// 我們只需要暴漏出io.flutter.plugin.*
// 不需要暴漏依賴項(xiàng)日月,transitive的默認(rèn)值是true,gradle會(huì)自動(dòng)添加子依賴缤骨,此處表示不添加子依賴
transitive = false
}
}
}
這個(gè)方法的主要作用就是添加完依賴項(xiàng)后執(zhí)行上傳maven任務(wù)爱咬,下面來看看上傳的方法addAarTask
:
void addAarTask(Project project, variant) {
String variantName = variant.name.capitalize()
String taskName = "assembleAar$variantName"
project.tasks.create(name: taskName) {
//檢查是否配置`uploadArchives`
if (!project.gradle.startParameter.taskNames.contains(taskName)) {
return
}
// 以下是上傳maven配置
project.uploadArchives.repositories.mavenDeployer {
pom {
artifactId = "${project.name}_${variant.name.toLowerCase()}"
}
}
overrideDefaultPublishConfig(project, variant)
// Generate the Maven artifacts.
finalizedBy "uploadArchives"
}
}
上面兩個(gè)核心的打包aar的腳本我們已經(jīng)介紹完了,下一小節(jié)我們看如何修改這個(gè)腳本
三绊起、如何修改gradle打包aar腳本
我們修改打包腳本的主要原因是:
- 打包aar時(shí)能使用本地engine
- 將修改后的本地engine打包到aar中精拟,也就是engine產(chǎn)物
flutter.jar
和libflutter.so
文件打包進(jìn)aar
3.1、修改flutter.gradle
中的addFlutterDependencies
void addFlutterDependencies(buildType) {
String flutterBuildMode = buildModeFor(buildType)
if (!supportsBuildMode(flutterBuildMode)) {
return
}
// add local engine dependencies by panmin [start]
// 當(dāng)使用本地engine時(shí)添加flutter.jar和libflutter.so文件依賴
if(useLocalEngine()){
String engineOutPath = project.property('local-engine-out')
File engineOut = project.file(engineOutPath)
if (!engineOut.isDirectory()) {
throw new GradleException('local-engine-out must point to a local engine build')
}
// 本地engine的flutter.jar文件路徑
File flutterJar = Paths.get(engineOut.absolutePath, "flutter.jar").toFile()
if (!flutterJar.isFile()) {
throw new GradleException('Local engine build does not contain flutter.jar')
}
// 本地engine的libflutter.so文件路徑
File flutterSo = Paths.get(engineOut.absolutePath, "flutter_embedding_$flutterBuildMode").toFile()
project.dependencies {
// 添加自動(dòng)生成的`GeneratedPluginRegistrant.java`文件需要的@Keep和@NonNull需要的依賴庫
implementation 'androidx.annotation:annotation:1.1.0'
// add flutter jar & libflutter so
if (project.getConfigurations().findByName("api")) {
"${flutterBuildMode}Api" project.files(flutterJar)
"${flutterBuildMode}Api" project.files(flutterSo)
} else {
"${flutterBuildMode}Compile" project.files(flutterJar)
"${flutterBuildMode}Compile" project.files(flutterSo)
}
}
return;
}
// add local engine dependencies by panmin [end]
虱歪。蜂绎。。
}
3.2实蔽、修改aar_init_script.gradle
void configureProject(Project project, String outputDir) {
if (!project.hasProperty("android")) {
throw new GradleException("Android property not found.")
}
if (!project.android.hasProperty("libraryVariants")) {
throw new GradleException("Can't generate AAR on a non Android library project.");
}
project.apply plugin: "maven"
// add local engine dependencies by panmin [start]
if (project.hasProperty('local-engine-build-mode')){
String flutterBuildMode = project.property('local-engine-build-mode').toLowerCase()
project.android.libraryVariants.all { variant ->
String variantName = variant.name.capitalize().toLowerCase()
// 判斷當(dāng)前gradle.properties配置的打包的模式
if (variantName == flutterBuildMode) {
addAarTask(project, variant)
}
}
} else {
project.android.libraryVariants.all { variant ->
addAarTask(project, variant)
}
}
// add local engine dependencies by panmin [end]
project.version = project.version.replace("-SNAPSHOT", "")
荡碾。。局装。坛吁。
}
四、如何使用修改后的gradle腳本
4.1铐尚、配置.android
項(xiàng)目的gradle.properties
# 以打包armeabi-v7a架構(gòu)為例
local-engine-repo=engine/src/out/android_release # 這個(gè)自己通過gclient sync下載flutter engine的路徑
local-engine-out=engine/src/out/android_release # arm64平臺(tái)對(duì)應(yīng)使用android_release_arm64
local-engine-build-mode=release
未修改腳本前使用flutter build aar
時(shí)會(huì)報(bào)錯(cuò):
Could not determine the dependencies of task ':flutter:compileReleaseAidl'.
> Could not resolve all task dependencies for configuration ':flutter:releaseCompileClasspath'.
> Could not find any matches for io.flutter:flutter_embedding_release:+ as no versions of io.flutter:flutter_embedding_release are available.
Required by:
project :flutter
> Could not find any matches for io.flutter:armeabi_v7a_release:+ as no versions of io.flutter:armeabi_v7a_release are available.
Required by:
project :flutter
> Could not find any matches for io.flutter:arm64_v8a_release:+ as no versions of io.flutter:arm64_v8a_release are available.
Required by:
project :flutter
> Could not find any matches for io.flutter:x86_64_release:+ as no versions of io.flutter:x86_64_release are available.
Required by:
project :flutter
可能是ninja -C out/android_release
時(shí)生成的flutter_embedding_release.jar
不能通過maven引用拨脉,大家有什么好的解釋,歡迎留言區(qū)討論宣增。
4.2玫膀、打包aar命令
修改腳本后,因?yàn)?code>gradle.properties中配置了local-engine-build-mode=release
并且local-engine-out
是android_release
爹脾,也就是armeabi-v7a
版本的帖旨,所以這里執(zhí)行打release包的命令為:
# 對(duì)應(yīng)arm平臺(tái)的release模式
flutter build aar --target-platform=android-arm --no-debug --no-profile --verbose
# 對(duì)應(yīng)arm64平臺(tái)的release模式
flutter build aar --target-platform=android-arm64 --no-debug --no-profile --verbose
打包結(jié)果為:
這個(gè)是打包后的結(jié)果箕昭,flutter.jar
和libflutter.so
已經(jīng)打包進(jìn)去了,這個(gè)aar產(chǎn)物直接交給Android原生工程使用的話就能直接使用了解阅。
五落竹、總結(jié)
這篇主要將了如何使用已經(jīng)編譯后flutter engine產(chǎn)物flutter.jar
和libflutter.so
,依賴修改了flutter.gradle
和aar_init_script.gradle
的打包腳本货抄,實(shí)現(xiàn)了產(chǎn)物嵌入述召,方便Android混合工程開發(fā)。但是還是有些不方便的地方就是大家都需要去下載蟹地、修改积暖、編譯flutter engine,下一篇文章我會(huì)講下如何把編譯產(chǎn)物上傳maven庫怪与,然后再次修改打包腳本夺刑,方便大家無腦使用,歡迎大家關(guān)注和點(diǎn)贊琼梆,也歡迎大家在留言區(qū)溝通交流性誉。