In the previous article we learned how to modify the Flutter Engine code to achieve dynamic effects. This article describes the process of flutter build AAR and then modify the corresponding Gradle compilation script to create aar packages suitable for hybrid projects.
The result of flutter build AAR
In this section, let’s take a look at the structure of a FLUTTER Build AAR that can be packaged normally
1.1. Preconditions
Create a new Android project and create a flutter module. You can also create a flutter module using flutter create -t module –org com.example flutter_module.
CD flutter_module and execute flutter pub get to automatically create an. Android file
1.2. Execute flutter build aar
We only analyze aar of release version here, change the suffix of Flutter_release-1.0.aar to JAR, and then open Flutter_release-1.0.jar with decomcompiling tool JD-GUI. The result is as follows:
You can see that there is no code for flutter. Jar or libflutter. So in the package, where are these two files?
How do you package these two files into an AAR? With that in mind let’s take a look at what scripts are executed when flutter Build AAR is executed.
Here is a solution, that isfat-aar
To package AAR, please use your own baidu
Ii. Process analysis of Flutter build AAR
This section describes the two gradle files involved in the build process of the flutter command: flutter. Gradle and aar_init_script.gradle
2.1, flutter. Gradle
In: build of Flutter. Gradle cited the apply in the from: “$flutterRoot/packages/flutter_tools/gradle/Flutter. Gradle.” “
/ / reference the plugin
apply plugin: FlutterPlugin
// This is followed by the implementation of plugin
class FlutterPlugin implements Plugin<Project> {
void apply(Project project) {
// Create extension fields source, target
project.extensions.create("flutter", FlutterExtension)
// Execute addFlutterTasks after other tasks are complete (set flutter initializers)
project.afterEvaluate this.&addFlutterTasks
// Abi configuration
if(shouldSplitPerAbi ())... .// Get the version of engine for easy download from Maven
engineVersion = useLocalEngine() ? "+" : "1.0.0 -" + Paths.get(flutterRoot.absolutePath, "bin"."internal"."engine.version"). ToFile (). The text. The trim ()...Gradle.properties (); // If you use a local engine, you need to configure 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
}
// Add dependencies for each type
project.android.buildTypes.each this.&addFlutterDependencies
project.android.buildTypes.whenObjectAdded this.&addFlutterDependencies
}
}
Copy the code
The apply method configures dependencies and other dependencies. The addFlutterDependencies method does the following:
/** * Adds the dependencies required by the Flutter project. * This includes: * 1. The embedding * 2. libflutter.so */
// This method is used to add flutter. Jar and libflutter. So
void addFlutterDependencies(buildType) {
String flutterBuildMode = buildModeFor(buildType)
// supportsBuildMode determines whether the local-engine-build-Mode in gradle.properites is the same as the current flutterBuildMode only if the local engine is used
if(! supportsBuildMode(flutterBuildMode)) {return
}
// Set the maven source path
String repository = useLocalEngine() ? project.property('local-engine-repo') : MAVEN_REPO
project.rootProject.allprojects {
repositories {
maven {
url repository
}
}
}
// Add the embedding dependency.
// Add a reference to flutter. Jar
addApiDependencies(project, buildType.name, "io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion")... platforms.each { platform -> String arch = PLATFORM_ARCH_MAP[platform].replace("-"."_")
// Add libflutter. So dependency
addApiDependencies(project, buildType.name,
"io.flutter:${arch}_$flutterBuildMode:$engineVersion")}}Copy the code
2.2, aar_init_script. Gradle
The script is there will be a flutter build aar triggered, file path $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
}
// For hybrid engineering, ':flutter' module
Project moduleProject = rootProject.subprojects.find { it.name == "flutter" }
assertmoduleProject ! =null
assert moduleProject.hasProperty("output-dir")
configureProject(moduleProject, moduleProject.property("output-dir"))
// Get all plugin subprojectsSet<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()
// Execute the moduleProject task after the plugin's 'assembleAar$variantName' task is complete
moduleProject.tasks.findByPath("assembleAar$variantName")
.dependsOn(pluginProject.tasks.findByPath("assembleAar$variantName"))}}}Copy the code
As you can see from the script above, there is a core method called configureProject. Let’s see what this method does:
void configureProject(Project project, String outputDir) {
// Ensure that the project is Android
if(! project.hasProperty("android")) {
throw new GradleException("Android property not found.")}// Make sure it is library instead of application
if(! project.android.hasProperty("libraryVariants")) {
throw new GradleException("Can't generate AAR on a non Android library project.");
}
// Use the Maven plugin
project.apply plugin: "maven"
project.android.libraryVariants.all { variant ->
// Execute this task after uploading Maven task is complete
addAarTask(project, variant)
}
// Upload maven path, here is a use of maven's local library
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 currently does not support using a local 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")}// Add repositories and dependencies
project.repositories {
maven {
url "http://download.flutter.io"
}
}
String engineVersion = Paths.get(getFlutterRoot(project), "bin"."internal"."engine.version").toFile().text.trim()
project.dependencies {
// Add a flutter. Jar dependency
compileOnly ("IO. Flutter: flutter_embedding_release: 1.0.0 - $engineVersion") {
// We just need to leak IO. Flutter. Plugin.*
// There is no need to expose dependencies. The default value of transitive is true. Gradle automatically adds child dependencies
transitive = false}}}Copy the code
This method is used to upload the maven task after adding the dependency. Let’s look at the addAarTask:
void addAarTask(Project project, variant) {
String variantName = variant.name.capitalize()
String taskName = "assembleAar$variantName"
project.tasks.create(name: taskName) {
// Check whether 'uploadArchives' is configured
if(! project.gradle.startParameter.taskNames.contains(taskName)) {return
}
// Upload maven configuration
project.uploadArchives.repositories.mavenDeployer {
pom {
artifactId = "${project.name}_${variant.name.toLowerCase()}"
}
}
overrideDefaultPublishConfig(project, variant)
// Generate the Maven artifacts.
finalizedBy "uploadArchives"}}Copy the code
Now that we have covered the script for the two core aar packages, how can we modify this script in the next section
How to modify gradle package AAR script
The main reasons we changed the packaging script were:
- The local engine can be used when the AAR is packaged
- Package the modified local engine into an AAR, which is the Engine artifact
flutter.jar
andlibflutter.so
The file is packaged into the AAR
3.1, modify,flutter.gradle
In theaddFlutterDependencies
void addFlutterDependencies(buildType) {
String flutterBuildMode = buildModeFor(buildType)
if(! supportsBuildMode(flutterBuildMode)) {return
}
// add local engine dependencies by panmin [start]
// Add flutter. Jar and libflutter. So file dependencies when using local engine
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')}// The path to the local engine's flutter. Jar file
File flutterJar = Paths.get(engineOut.absolutePath, "flutter.jar").toFile()
if(! flutterJar.isFile()) {throw new GradleException('Local engine build does not contain flutter.jar')}// The libflutter. So file path of the local engine
File flutterSo = Paths.get(engineOut.absolutePath, "flutter_embedding_$flutterBuildMode").toFile()
project.dependencies {
/ / add automatically generated ` GeneratedPluginRegistrant. Java ` files need @ Keep and @ NonNull need to rely on libraries
implementation 'androidx. Annotation: the 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]. }Copy the code
3.2. Modify 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()
// Determine the packaging mode of the current gradle.properties configuration
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"."")... }Copy the code
How to use the modified Gradle script
4.1, configuration,.android
Project of gradle. The properties
#Take packaging the Armeabi-V7A architecture as an exampleLocal-engine-repo =engine/ SRC /out/android_release # Local-engine-out =engine/ SRC /out/android_release # arm64 Android_release_arm64 local-engine-build-mode=releaseCopy the code
Error when using flutter Build AAR without modifying the script:
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
Copy the code
Flutter_embedding_release. jar is not referenced by Maven when ninja -c out/ Android_release is generated.
4.2 Package aar command
Gradle. properties is configured with local-engine-build-mode=release and local-engine-out is android_release. So the command to release the package is:
#Release mode corresponding to arm platform
flutter build aar --target-platform=android-arm --no-debug --no-profile --verbose
#The release mode corresponds to the ARM64 platform
flutter build aar --target-platform=android-arm64 --no-debug --no-profile --verbose
Copy the code
The packing result is:
This is the result of the package, the flutter. Jar and libflutter. So have been packaged, and this AAR product can be used directly if delivered to Android native projects.
Five, the summary
Gradle and aar_init_script.gradle are packaged with the buildingof the flutter engine, including the buildingof the flutter engine, and the buildingof the flutter engine. Convenient Android hybrid engineering development. In the next article, I will explain how to upload the build product to the Maven library and then modify the package script again for your brainless use. Welcome to follow and like the flutter engine, as well as communicate in the comments section.