一、引入flutter.gradle文件
基于flutter1.9.1版本。
Flutter项目android工程app主模块,引入flutter.gradle配置文件,该文件在flutter sdk的flutter/packages/flutter_tools/gradle/目录下,目的是在普通android工程的编译打包流程中插入一些Flutter任务。
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
app主模块,当Gradle运行到apply from时,进入flutter.gradle执行,代码流程。
在flutter.gradle文件,首先执行buildscript代码块,然后顺序执行,代码结构。
定义一个FlutterPlugin插件,实现接口Plugin<Project>的apply方法,Gradle运行到apply plugin: FlutterPlugin
语句时,去执行apply方法(插入任务),执行结束回到app主模块,继续主模块Gradle文件后面的代码。
FlutterTask任务类、FlutterPluginTask任务类。
引入flutter.gradle的配置文件仅执行buildscript代码块和FlutterPlugin插件的apply方法,目的是插入Flutter任务。
二、插件
定义FlutterPlugin插件,实现接口Plugin<Project>,apply方法。
@Override
void apply(Project project) {
}
Project代表android工程的app模块,project.getName()
是app。
project.afterEvaluate this.&addFlutterTasks
afterEvaluate,当apply()方法结束,project(app模块)的Gradle完成,再添加Flutter任务,调用addFlutterTasks()方法。
String flutterRootPath = resolveProperty(project, "flutter.sdk", System.env.FLUTTER_ROOT)
查找父目录下的local.properties
文件,即(工程根目录),获取flutter.sdk路径和bin目录下可执行文件。
String flutterExecutableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "flutter.bat" : "flutter"
flutterExecutable = Paths.get(flutterRoot.absolutePath, "bin", flutterExecutableName).toFile();
根据不同平台去加载可执行文件。
# basePlatform目标平台默认:android-arm64
String basePlatformArch = getBasePlatform(project)
Path baseEnginePath = Paths.get(flutterRoot.absolutePath, "bin", "cache", "artifacts", "engine")
File debugJar = baseEnginePath.resolve("${basePlatformArch}").resolve("flutter.jar").toFile()
baseJar["debug"] = debugJar
baseJar["profile"] = baseEnginePath.resolve("${basePlatformArch}-profile").resolve("flutter.jar").toFile()
baseJar["release"] = baseEnginePath.resolve("${basePlatformArch}-release").resolve("flutter.jar").toFile()
从sdk的/bin/cache/artifacts/engine/
路径,创建flutter.jar文件的Flie,三种构建模式debug,profile和release,从android-arm64-xxx对应目录加载。
project.android.buildTypes.each {
def buildMode = buildModeFor(it)
println "each buildTypes 构建类型: $buildMode 添加flutter.jar依赖"
addApiDependencies(project, it.name, project.files {
baseJar[buildMode]
})
}
遍历构建模式,通过project.dependencies.add()
方法,添加android主模块对flutter.jar的依赖,project是android工程的app模块。
if (project.getConfigurations().findByName("api")) {
configuration = "${variantName}Api";
} else {
configuration = "${variantName}Compile";
}
project.dependencies.add(configuration, dependency, config)
构建类型XxxApi,依赖文件。
三、任务
插件apply()完成,afterEvaluate设置addFlutterTasks()任务添加方法执行。
private void addFlutterTasks(Project project) {
}
通过project.tasks.create()
方法添加。
## 目标平台:[android-arm, android-arm64]
def targetPlatforms = getTargetPlatforms(project)
默认平台是arm和arm64。
1,编译任务
FlutterTask compileTask = project.tasks.create(name: taskName, type: FlutterTask) {
}
任务名:compileFlutterDebug构建模式+平台,类型是FlutterTask类,自定义任务类。
compileFlutterBuildXxxArm,compileFlutterBuildXxxArm64
构建模式:Debug,Profile,Release
abi平台:Arm(32)和Arm64
addFlutterTasks方法仅将任务添加到Gradle的构建流程中,运行在编译过程中触发。
FlutterTask类build方法,父类DefaultTask的buildBundle()方法。
@TaskAction
void build() {
buildBundle()
}
编译任务生成Dart产物build目录:intermediates/flutter/xxx/平台/。在平台目录下,产物debug和release模式不同,
debug模式:flutter_assets目录下kernel_blob.bin,vm_snapshot_data,isolate_snapshot_data。
releass模式:flutter_assets目录+app.so。
2,lib任务
Task packFlutterSnapshotsAndLibsTask = project.tasks.create(name:
"packLibs${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}", type: Jar) {
}
任务名:packLibsflutterBuild构建模式,类型是Jar类,Gradle内置任务类,将sdk中对应平台libflutter.so文件写入libs.jar压缩包。
packLibsflutterBuildXxx,依赖对应编译任务
构建模式:Debug,Profile,Release
abi平台:依赖编译任务生成的目标平台
debug模式,增加两个平台。
if (flutterBuildMode == 'debug') {
libFlutterPlatforms.add('android-x86')
libFlutterPlatforms.add('android-x64')
}
在build/intermediates/flutter/xxx目录,定义一个libs.jar文件,将sdk的engine平台flutter.jar中lib目录下的so文件(lib/**)复制到压缩包libs.jar,当debug模式,多复制x86和x64平台的libflutter.so文件。其他模式,复制android-arm-xxx(32位)目录中的文件。
将intermediates/flutter/release/android-arm和64的so文件(app.so),release模式编译过程,Dart产物包括so文件,重命名libapp.so,拷贝到libs.jar压缩包文件。
// 包含so产物的intermediates/flutter/平台/,release和profile
compileTasks.each { compileTask ->
from(compileTask.intermediateDir) {
include '*.so'
rename { String filename ->
println "rename:"+compileTask.intermediateDir
return "lib/${compileTask.abi}/lib${filename}"
}
}
}
3,拷贝任务
Task copyFlutterAssetsTask = project.tasks.create(name:
"copyFlutterAssets${variant.name.capitalize()}", type: Copy) {
}
任务名:copyFlutterAssets构建模式,类型是Copy类,Gradle内置任务类,
copyFlutterAssetsXxx,依赖对应编译任务和packLibsflutterBuild任务
构建类模式:Debug,Profile,Release
abi平台:依赖编译任务生成的目标平台
依赖cleanMergeXxxAssets,mergeXxxAssets
# clean动作先执行
variant.mergeAssets.mustRunAfter("clean${variant.mergeAssets.name.capitalize()}")
拷贝是从intermediates的flutter目录到merged_assets目录下。
/build/intermediates/merged_assets/release/mergeReleaseAssets/out
拷贝内容是flutter_assets文件夹目录下/*。
addApiDependencies(project, variant.name, project.files {
packFlutterSnapshotsAndLibsTask
})
依赖packLibsflutterBuild任务。
## 运行拷贝任务
> Task :app:cleanMergeDebugAssets UP-TO-DATE
> Task :app:compileFlutterBuildDebugArm
> Task :app:compileFlutterBuildDebugArm64
> Task :app:mergeDebugShaders
> Task :app:compileDebugShaders
> Task :app:generateDebugAssets
> Task :app:packLibsflutterBuildDebug UP-TO-DATE
> Task :app:mergeDebugAssets
> Task :app:copyFlutterAssetsDebug
8 actionable tasks: 6 executed, 2 up-to-date
11:42:04: Task execution finished 'copyFlutterAssetsDebug'.
4,构建顺序
Debug模式,Gradle顺序。
四、Dart编译命令
BaseFlutterTask基类的buildBundle()方法,调用Flutter构建命令,生成Futter产物。
sourceDir目录,即根目录中,包含lib/main.dart文件的目录,添加任务时,构建目录默认是lib/main.dart,通过project.exec {..}
方法,执行命令。
void buildBundle() {
intermediateDir.mkdirs()
if (buildMode == "profile" || buildMode == "release") {
project.exec {
executable flutterExecutable.absolutePath
workingDir sourceDir
args "build", "aot"
args "--target", targetPath
args "--output-dir", "${intermediateDir}"
...//args参数
}
}
project.exec {
executable flutterExecutable.absolutePath
workingDir sourceDir
args "build", "bundle"
args "--target", targetPath
args "--target-platform", "${targetPlatform}"
...//args参数
args "--asset-dir", "${intermediateDir}/flutter_assets"
if (buildMode == "debug") {
args "--debug"
}
if (buildMode == "profile") {
args "--profile"
}
if (buildMode == "release") {
args "--release"
}
}
}
release和profile构建模式,两次命令,第一个project.exec。
flutter build aot --suppress-analytics --quiet --target lib/main.dart --target-platform android-arm --output-dir build/app/intermediates/flutter/release --release
输出目录是intermediates/flutter/release/平台/,产物是app.so文件,不支持debug构建模式。
所有构建模式,第二个project.exec。
flutter build bundle --suppress-analytics --target lib/main.dart --precompiled --asset-dir build/app/intermediates/flutter/release/flutter_assets --release
build bundle,产物是flutter_assets目录。
任重而道远