mirror of
https://github.com/flutter/flutter
synced 2024-09-19 16:21:58 +00:00
Refactor Gradle plugin (#34353)
This commit is contained in:
parent
361e8c75d7
commit
1c6cda9a0d
|
@ -80,82 +80,13 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
// to match.
|
||||
static final String FLUTTER_BUILD_PREFIX = "flutterBuild"
|
||||
|
||||
private Path baseEnginePath
|
||||
private Map baseJar = [:]
|
||||
private File flutterRoot
|
||||
private File flutterExecutable
|
||||
private String localEngine
|
||||
private String localEngineSrcPath
|
||||
private Properties localProperties
|
||||
private File flutterJar
|
||||
private File debugFlutterJar
|
||||
private File profileFlutterJar
|
||||
private File releaseFlutterJar
|
||||
private File dynamicProfileFlutterJar
|
||||
private File dynamicReleaseFlutterJar
|
||||
|
||||
private Properties readPropertiesIfExist(File propertiesFile) {
|
||||
Properties result = new Properties()
|
||||
if (propertiesFile.exists()) {
|
||||
propertiesFile.withReader('UTF-8') { reader -> result.load(reader) }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private List<String> getTargetPlatforms(Project project) {
|
||||
if (!project.hasProperty('target-platform')) {
|
||||
return DEFAULT_PLATFORMS
|
||||
}
|
||||
return project.property('target-platform').split(',').collect {
|
||||
if (!PLATFORM_ARCH_MAP[it]) {
|
||||
throw new GradleException("Invalid platform: $it.")
|
||||
}
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean getBuildShareLibrary(Project project) {
|
||||
if (project.hasProperty('build-shared-library')) {
|
||||
return project.property('build-shared-library').toBoolean()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Boolean splitPerAbi(Project project) {
|
||||
if (project.hasProperty('split-per-abi')) {
|
||||
return project.property('split-per-abi').toBoolean()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String resolveProperty(Project project, String name, String defaultValue) {
|
||||
if (localProperties == null) {
|
||||
localProperties = readPropertiesIfExist(new File(project.projectDir.parentFile, "local.properties"))
|
||||
}
|
||||
String result
|
||||
if (project.hasProperty(name)) {
|
||||
result = project.property(name)
|
||||
}
|
||||
if (result == null) {
|
||||
result = localProperties.getProperty(name)
|
||||
}
|
||||
if (result == null) {
|
||||
result = defaultValue
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the platform that is used to extract the `libflutter.so` and the .class files.
|
||||
*
|
||||
* Note: This is only needed to add the .class files.
|
||||
* Unfortunately, the engine artifacts include the .class and libflutter.so files.
|
||||
*/
|
||||
private String getBasePlatform(Project project) {
|
||||
if (PLATFORM_ARM64 in getTargetPlatforms(project)) {
|
||||
return PLATFORM_ARM64;
|
||||
}
|
||||
return PLATFORM_ARM32;
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
|
@ -165,7 +96,7 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
// By default, assembling APKs generates fat APKs if multiple platforms are passed.
|
||||
// Configuring split per ABI allows to generate separate APKs for each abi.
|
||||
// This is a noop when building a bundle.
|
||||
if (this.splitPerAbi(project)) {
|
||||
if (splitPerAbi(project)) {
|
||||
project.android {
|
||||
splits {
|
||||
abi {
|
||||
|
@ -179,7 +110,7 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
}
|
||||
}
|
||||
}
|
||||
this.getTargetPlatforms(project).each { targetArch ->
|
||||
getTargetPlatforms(project).each { targetArch ->
|
||||
String abiValue = PLATFORM_ARCH_MAP[targetArch]
|
||||
project.android {
|
||||
packagingOptions {
|
||||
|
@ -187,7 +118,7 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
// Prevent the ELF library from getting corrupted.
|
||||
doNotStrip "*/${abiValue}/libapp.so"
|
||||
}
|
||||
if (this.splitPerAbi(project)) {
|
||||
if (splitPerAbi(project)) {
|
||||
splits {
|
||||
abi {
|
||||
include abiValue
|
||||
|
@ -231,50 +162,7 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
String flutterExecutableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "flutter.bat" : "flutter"
|
||||
flutterExecutable = Paths.get(flutterRoot.absolutePath, "bin", flutterExecutableName).toFile();
|
||||
|
||||
if (project.hasProperty('localEngineOut')) {
|
||||
String engineOutPath = project.property('localEngineOut')
|
||||
File engineOut = project.file(engineOutPath)
|
||||
if (!engineOut.isDirectory()) {
|
||||
throw new GradleException('localEngineOut must point to a local engine build')
|
||||
}
|
||||
baseEnginePath = Paths.get(engineOut.absolutePath)
|
||||
flutterJar = baseEnginePath.resolve("flutter.jar").toFile()
|
||||
if (!flutterJar.isFile()) {
|
||||
throw new GradleException('Local engine jar not found: ' + flutterJar)
|
||||
}
|
||||
|
||||
localEngine = engineOut.name
|
||||
localEngineSrcPath = engineOut.parentFile.parent
|
||||
// The local engine is built for one of the build type.
|
||||
// However, we use the same engine for each of the build types.
|
||||
debugFlutterJar = flutterJar
|
||||
profileFlutterJar = flutterJar
|
||||
releaseFlutterJar = flutterJar
|
||||
dynamicProfileFlutterJar = flutterJar
|
||||
dynamicReleaseFlutterJar = flutterJar
|
||||
} else {
|
||||
String basePlatformArch = getBasePlatform(project)
|
||||
// This is meant to include the compiled classes only, however it will include `libflutter.so` as well.
|
||||
baseEnginePath = Paths.get(flutterRoot.absolutePath, "bin", "cache", "artifacts", "engine")
|
||||
debugFlutterJar = baseEnginePath.resolve("${basePlatformArch}").resolve("flutter.jar").toFile()
|
||||
profileFlutterJar = baseEnginePath.resolve("${basePlatformArch}-profile").resolve("flutter.jar").toFile()
|
||||
releaseFlutterJar = baseEnginePath.resolve("${basePlatformArch}-release").resolve("flutter.jar").toFile()
|
||||
dynamicProfileFlutterJar = baseEnginePath.resolve("${basePlatformArch}-dynamic-profile").resolve("flutter.jar").toFile()
|
||||
dynamicReleaseFlutterJar = baseEnginePath.resolve("${basePlatformArch}-dynamic-release").resolve("flutter.jar").toFile()
|
||||
}
|
||||
|
||||
if (!debugFlutterJar.isFile()) {
|
||||
project.exec {
|
||||
executable flutterExecutable.absolutePath
|
||||
args "--suppress-analytics"
|
||||
args "precache"
|
||||
}
|
||||
if (!debugFlutterJar.isFile()) {
|
||||
throw new GradleException("Unable to find flutter.jar in SDK: ${debugFlutterJar}")
|
||||
}
|
||||
}
|
||||
|
||||
// Add x86/x86_64 native library. Debug mode only, for now.
|
||||
// x86/x86_64 native library used for debugging only, for now.
|
||||
File flutterX86Jar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/flutter-x86.jar")
|
||||
Task debugX86JarTask = project.tasks.create("${FLUTTER_BUILD_PREFIX}X86Jar", Jar) {
|
||||
destinationDir flutterX86Jar.parentFile
|
||||
|
@ -286,13 +174,62 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
into 'lib/x86_64'
|
||||
}
|
||||
}
|
||||
// Add flutter.jar dependencies to all <buildType>Api configurations, including custom ones
|
||||
// added after applying the Flutter plugin.
|
||||
project.android.buildTypes.each {
|
||||
addFlutterJarApiDependency(project, it, debugX86JarTask)
|
||||
}
|
||||
project.android.buildTypes.whenObjectAdded {
|
||||
addFlutterJarApiDependency(project, it, debugX86JarTask)
|
||||
|
||||
if (useLocalEngine(project)) {
|
||||
String engineOutPath = project.property('localEngineOut')
|
||||
File engineOut = project.file(engineOutPath)
|
||||
if (!engineOut.isDirectory()) {
|
||||
throw new GradleException('localEngineOut must point to a local engine build')
|
||||
}
|
||||
Path baseEnginePath = Paths.get(engineOut.absolutePath)
|
||||
flutterJar = baseEnginePath.resolve("flutter.jar").toFile()
|
||||
if (!flutterJar.isFile()) {
|
||||
throw new GradleException("Local engine jar not found: $flutterJar")
|
||||
}
|
||||
localEngine = engineOut.name
|
||||
localEngineSrcPath = engineOut.parentFile.parent
|
||||
// The local engine is built for one of the build type.
|
||||
// However, we use the same engine for each of the build types.
|
||||
project.android.buildTypes.each {
|
||||
addApiDependencies(project, it, project.files {
|
||||
[debugX86JarTask, flutterJar]
|
||||
})
|
||||
}
|
||||
} else {
|
||||
String basePlatformArch = getBasePlatform(project)
|
||||
// This is meant to include the compiled classes only, however it will include `libflutter.so` as well.
|
||||
Path baseEnginePath = Paths.get(flutterRoot.absolutePath, "bin", "cache", "artifacts", "engine")
|
||||
File debugJar = baseEnginePath.resolve("${basePlatformArch}").resolve("flutter.jar").toFile()
|
||||
baseJar["debug"] = [debugX86JarTask, debugJar]
|
||||
if (!debugJar.isFile()) {
|
||||
project.exec {
|
||||
executable flutterExecutable.absolutePath
|
||||
args "--suppress-analytics"
|
||||
args "precache"
|
||||
}
|
||||
if (!debugJar.isFile()) {
|
||||
throw new GradleException("Unable to find flutter.jar in SDK: ${debugJar}")
|
||||
}
|
||||
}
|
||||
baseJar["profile"] = baseEnginePath.resolve("${basePlatformArch}-profile").resolve("flutter.jar").toFile()
|
||||
baseJar["release"] = baseEnginePath.resolve("${basePlatformArch}-release").resolve("flutter.jar").toFile()
|
||||
baseJar["dynamicProfile"] = baseEnginePath.resolve("${basePlatformArch}-dynamic-profile").resolve("flutter.jar").toFile()
|
||||
baseJar["dynamicRelease"] = baseEnginePath.resolve("${basePlatformArch}-dynamic-release").resolve("flutter.jar").toFile()
|
||||
|
||||
// Add flutter.jar dependencies to all <buildType>Api configurations, including custom ones
|
||||
// added after applying the Flutter plugin.
|
||||
project.android.buildTypes.each {
|
||||
def buildMode = buildModeFor(it)
|
||||
addApiDependencies(project, it, project.files {
|
||||
baseJar[buildMode]
|
||||
})
|
||||
}
|
||||
project.android.buildTypes.whenObjectAdded {
|
||||
def buildMode = buildModeFor(it)
|
||||
addApiDependencies(project, it, project.files {
|
||||
baseJar[buildMode]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
File pluginsFile = new File(project.projectDir.parentFile.parentFile, '.flutter-plugins')
|
||||
|
@ -322,6 +259,75 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
}
|
||||
}
|
||||
|
||||
private String resolveProperty(Project project, String name, String defaultValue) {
|
||||
if (localProperties == null) {
|
||||
localProperties = readPropertiesIfExist(new File(project.projectDir.parentFile, "local.properties"))
|
||||
}
|
||||
String result
|
||||
if (project.hasProperty(name)) {
|
||||
result = project.property(name)
|
||||
}
|
||||
if (result == null) {
|
||||
result = localProperties.getProperty(name)
|
||||
}
|
||||
if (result == null) {
|
||||
result = defaultValue
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private static Properties readPropertiesIfExist(File propertiesFile) {
|
||||
Properties result = new Properties()
|
||||
if (propertiesFile.exists()) {
|
||||
propertiesFile.withReader('UTF-8') { reader -> result.load(reader) }
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private static List<String> getTargetPlatforms(Project project) {
|
||||
if (!project.hasProperty('target-platform')) {
|
||||
return DEFAULT_PLATFORMS
|
||||
}
|
||||
return project.property('target-platform').split(',').collect {
|
||||
if (!PLATFORM_ARCH_MAP[it]) {
|
||||
throw new GradleException("Invalid platform: $it.")
|
||||
}
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean getBuildShareLibrary(Project project) {
|
||||
if (project.hasProperty('build-shared-library')) {
|
||||
return project.property('build-shared-library').toBoolean()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Boolean splitPerAbi(Project project) {
|
||||
if (project.hasProperty('split-per-abi')) {
|
||||
return project.property('split-per-abi').toBoolean()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Boolean useLocalEngine(Project project) {
|
||||
return project.hasProperty('localEngineOut')
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the platform that is used to extract the `libflutter.so` and the .class files.
|
||||
*
|
||||
* Note: This is only needed to add the .class files.
|
||||
* Unfortunately, the engine artifacts include the .class and libflutter.so files.
|
||||
*/
|
||||
private static String getBasePlatform(Project project) {
|
||||
if (PLATFORM_ARM64 in getTargetPlatforms(project)) {
|
||||
return PLATFORM_ARM64;
|
||||
}
|
||||
return PLATFORM_ARM32;
|
||||
}
|
||||
|
||||
// TODO(blasten): Clean this up.
|
||||
private void addFlutterJarCompileOnlyDependency(Project project) {
|
||||
if (project.state.failure) {
|
||||
return
|
||||
|
@ -334,54 +340,33 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
provided project.files(flutterJar)
|
||||
}
|
||||
} else {
|
||||
assert baseJar["debug"].last().isFile()
|
||||
assert baseJar["profile"].isFile()
|
||||
assert baseJar["release"].isFile()
|
||||
|
||||
if (project.getConfigurations().findByName("debugCompileOnly")) {
|
||||
debugCompileOnly project.files(debugFlutterJar)
|
||||
profileCompileOnly project.files(profileFlutterJar)
|
||||
releaseCompileOnly project.files(releaseFlutterJar)
|
||||
debugCompileOnly project.files(baseJar["debug"])
|
||||
profileCompileOnly project.files(baseJar["profile"])
|
||||
releaseCompileOnly project.files(baseJar["release"])
|
||||
} else {
|
||||
debugProvided project.files(debugFlutterJar)
|
||||
profileProvided project.files(profileFlutterJar)
|
||||
releaseProvided project.files(releaseFlutterJar)
|
||||
debugProvided project.files(baseJar["debug"])
|
||||
profileProvided project.files(baseJar["profile"])
|
||||
releaseProvided project.files(baseJar["release"])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds suitable flutter.jar api dependencies to the specified buildType.
|
||||
*
|
||||
* Note: The BuildType DSL type is not public, and is therefore omitted from the signature.
|
||||
*/
|
||||
private void addFlutterJarApiDependency(Project project, buildType, Task debugX86JarTask) {
|
||||
private static void addApiDependencies(Project project, buildType, FileCollection files) {
|
||||
project.dependencies {
|
||||
String configuration;
|
||||
// `compile` dependencies are now `api` dependencies.
|
||||
if (project.getConfigurations().findByName("api")) {
|
||||
configuration = buildType.name + "Api";
|
||||
} else {
|
||||
configuration = buildType.name + "Compile";
|
||||
}
|
||||
add(configuration, project.files {
|
||||
String buildMode = buildModeFor(buildType)
|
||||
switch (buildMode) {
|
||||
case "debug":
|
||||
[debugX86JarTask, debugFlutterJar]
|
||||
break
|
||||
case "profile":
|
||||
profileFlutterJar
|
||||
break
|
||||
case "dynamicProfile":
|
||||
dynamicProfileFlutterJar
|
||||
break
|
||||
case "dynamicRelease":
|
||||
dynamicReleaseFlutterJar
|
||||
break
|
||||
case "release":
|
||||
releaseFlutterJar
|
||||
break
|
||||
default:
|
||||
throw new GradleException("Invalid build mode: ${buildMode}")
|
||||
}
|
||||
})
|
||||
add(configuration, files)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -475,9 +460,9 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
extraGenSnapshotOptionsValue = project.property('extra-gen-snapshot-options')
|
||||
}
|
||||
|
||||
def targetPlatforms = this.getTargetPlatforms(project)
|
||||
def targetPlatforms = getTargetPlatforms(project)
|
||||
def addFlutterDeps = { variant ->
|
||||
if (this.splitPerAbi(project)) {
|
||||
if (splitPerAbi(project)) {
|
||||
variant.outputs.each { output ->
|
||||
// Assigns the new version code to versionCodeOverride, which changes the version code
|
||||
// for only the output APK, not for the variant itself. Skipping this step simply
|
||||
|
@ -539,13 +524,14 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
// This check prevents including `libflutter.so` twice, since it's included in the base platform jar.
|
||||
// Unfortunately, the `pickFirst` setting in `packagingOptions` does not work when the project `:flutter`
|
||||
// is included as an implementation dependency, which causes duplicated `libflutter.so`.
|
||||
if (getBasePlatform(project) != targetArch) {
|
||||
def engineArtifactSubdir = getEngineArtifactDirName(variant.buildType, targetArch);
|
||||
// Include `libflutter.so`.
|
||||
// TODO(blasten): The libs should be outside `flutter.jar` when the artifacts are downloaded.
|
||||
from(project.zipTree("${flutterRoot}/bin/cache/artifacts/engine/${engineArtifactSubdir}/flutter.jar")) {
|
||||
include 'lib/**'
|
||||
}
|
||||
if (getBasePlatform(project) == targetArch) {
|
||||
return
|
||||
}
|
||||
def engineArtifactSubdir = getEngineArtifactDirName(variant.buildType, targetArch);
|
||||
// Include `libflutter.so`.
|
||||
// TODO(blasten): The libs should be outside `flutter.jar` when the artifacts are downloaded.
|
||||
from(project.zipTree("${flutterRoot}/bin/cache/artifacts/engine/${engineArtifactSubdir}/flutter.jar")) {
|
||||
include 'lib/**'
|
||||
}
|
||||
}
|
||||
dependsOn flutterTasks
|
||||
|
@ -560,17 +546,10 @@ class FlutterPlugin implements Plugin<Project> {
|
|||
}
|
||||
}
|
||||
// Include the snapshots and libflutter.so in `lib/`.
|
||||
project.dependencies {
|
||||
String configuration;
|
||||
if (project.getConfigurations().findByName("api")) {
|
||||
configuration = buildType.name + "Api";
|
||||
} else {
|
||||
configuration = buildType.name + "Compile";
|
||||
}
|
||||
add(configuration, project.files {
|
||||
packFlutterSnapshotsAndLibsTask
|
||||
})
|
||||
}
|
||||
addApiDependencies(project, buildType, project.files {
|
||||
packFlutterSnapshotsAndLibsTask
|
||||
})
|
||||
|
||||
// We know that the flutter app is a subproject in another Android app when these tasks exist.
|
||||
Task packageAssets = project.tasks.findByPath(":flutter:package${variant.name.capitalize()}Assets")
|
||||
Task cleanPackageAssets = project.tasks.findByPath(":flutter:cleanPackage${variant.name.capitalize()}Assets")
|
||||
|
|
Loading…
Reference in a new issue