Fix warnings in FGP (#166727)

Fixes/suppresses all warnings:

1. Fixes https://github.com/flutter/flutter/issues/162695
2. Suppresses warnings about the various `*Variant*` imports that we use
being deprecated, with comments linking to
https://github.com/flutter/flutter/issues/166550 to migrate to the
variant api.
3. Fixes some unused elvis operators and unneeded types provided for
declarations that AGP complains about, e.g. `val fooString: String = "a
string"`, and use of deprecated string related methods.
4. Follows up on https://github.com/flutter/flutter/pull/166277, as we
were getting a warning mentioned in this comment
https://github.com/flutter/flutter/pull/166277#issuecomment-2780184486.
5. Suppresses some warnings about unused code where the analysis
couldn't properly detect it being used (i.e., it isn't unused)

(4) is more opinionated, let me know if you think it should be done in a
follow up.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

---------

Co-authored-by: Gray Mackall <mackall@google.com>
This commit is contained in:
Gray Mackall 2025-04-08 11:37:14 -07:00 committed by GitHub
parent a2cb910f83
commit e2dea95082
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 143 additions and 87 deletions

View File

@ -157,14 +157,7 @@ Future<void> main() async {
final String defaultPath = path.join(project.rootPath, 'android', 'app', '.cxx');
final String modifiedPath = path.join(
project.rootPath,
'build',
'app',
'intermediates',
'flutter',
'.cxx',
);
final String modifiedPath = path.join(project.rootPath, 'build', '.cxx');
if (Directory(defaultPath).existsSync()) {
throw TaskResult.failure('Producing unexpected build artifacts in $defaultPath');
}

View File

@ -19,16 +19,6 @@ tasks.validatePlugins {
enableStricterValidation.set(true)
}
// We need to compile Kotlin first so we can call it from Groovy. See https://stackoverflow.com/q/36214437/7009800
tasks.withType<GroovyCompile> {
dependsOn(tasks.compileKotlin)
classpath += files(tasks.compileKotlin.get().destinationDirectory)
}
tasks.classes {
dependsOn(tasks.compileGroovy)
}
gradlePlugin {
plugins {
// The "flutterPlugin" name isn't used anywhere.

View File

@ -10,10 +10,10 @@ import kotlinx.serialization.json.put
// TODO(gmackall): Identify which of these can be val instead of var.
class Deeplink(
var scheme: String?,
var host: String?,
private var scheme: String?,
private var host: String?,
var path: String?,
var intentFilterCheck: IntentFilterCheck
private var intentFilterCheck: IntentFilterCheck
) {
// TODO(gmackall): This behavior was kept identical to the original Groovy behavior as part of
// the Groovy->Kotlin conversion, but should be changed once the conversion is complete.

View File

@ -22,6 +22,7 @@ private const val FLUTTER_SDK_PATH = "flutterSdkPath"
* This plugin applies the native plugin loader plugin (../scripts/native_plugin_loader.gradle.kts)
* and then configures the main project to `include` each of the loaded flutter plugins.
*/
@Suppress("unused") // This class is used by packages/flutter_tools/gradle/build.gradle.kts.
class FlutterAppPluginLoaderPlugin : Plugin<Settings> {
override fun apply(settings: Settings) {
val flutterProjectRoot: File = settings.settingsDir.parentFile

View File

@ -17,6 +17,7 @@ import org.gradle.api.GradleException
* Learn more about extensions in Gradle:
* * https://docs.gradle.org/8.0.2/userguide/custom_plugins.html#sec:getting_input_from_the_build
*/
@Suppress("unused") // The values in this class are used in Flutter developers app-level build.gradle file.
open class FlutterExtension {
/** Sets the compileSdkVersion used by default in Flutter app projects. */
val compileSdkVersion: Int = 35

View File

@ -4,14 +4,10 @@
package com.flutter.gradle
import com.android.build.VariantOutput
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.gradle.AbstractAppExtension
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.api.ApkVariantOutput
import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.api.BaseVariantOutput
import com.android.build.gradle.tasks.PackageAndroidArtifact
import com.android.build.gradle.tasks.ProcessAndroidResources
import com.flutter.gradle.FlutterPluginUtils.readPropertiesIfExist
@ -27,6 +23,8 @@ import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import org.gradle.internal.os.OperatingSystem
import org.gradle.kotlin.dsl.support.serviceOf
import org.gradle.process.ExecOperations
import java.io.File
import java.nio.charset.StandardCharsets
import java.nio.file.Paths
@ -54,7 +52,7 @@ class FlutterPlugin : Plugin<Project> {
val flutterRootSystemVal: String? = System.getenv("FLUTTER_ROOT")
val flutterRootPath: String =
resolveProperty("flutter.sdk", flutterRootSystemVal)
resolveFlutterSdkProperty(flutterRootSystemVal)
?: throw GradleException(
"Flutter SDK not found. Define location with flutter.sdk in the " +
"local.properties file or with a FLUTTER_ROOT environment variable."
@ -145,7 +143,7 @@ class FlutterPlugin : Plugin<Project> {
isUniversalApk = false
}
}
val propDeferredComponentNames: String = "deferred-component-names"
val propDeferredComponentNames = "deferred-component-names"
val deferredComponentNamesValue: String? =
project.findProperty(propDeferredComponentNames) as? String
if (deferredComponentNamesValue != null) {
@ -280,10 +278,8 @@ class FlutterPlugin : Plugin<Project> {
private fun getExecutableNameForPlatform(baseExecutableName: String): String =
if (OperatingSystem.current().isWindows) "$baseExecutableName.bat" else baseExecutableName
private fun resolveProperty(
propertyName: String,
defaultValue: String?
): String? {
private fun resolveFlutterSdkProperty(defaultValue: String?): String? {
val propertyName = "flutter.sdk"
if (localProperties == null) {
localProperties =
readPropertiesIfExist(File(project!!.projectDir.parentFile, "local.properties"))
@ -300,7 +296,8 @@ class FlutterPlugin : Plugin<Project> {
rootProject.subprojects.forEach { subproject ->
val gradlew: String =
getExecutableNameForPlatform("${rootProject.projectDir}/gradlew")
rootProject.exec {
val execOps = rootProject.serviceOf<ExecOperations>()
execOps.exec {
workingDir(rootProject.projectDir)
executable(gradlew)
args(":${subproject.name}:dependencies", "--write-locks")
@ -342,11 +339,18 @@ class FlutterPlugin : Plugin<Project> {
}
val copyFlutterAssetsTask: Task =
addFlutterDeps(variant, flutterPlugin, targetPlatforms)
val variantOutput: BaseVariantOutput = variant.outputs.first()
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
val variantOutput: com.android.build.gradle.api.BaseVariantOutput = variant.outputs.first()
val processResources: ProcessAndroidResources =
try {
variantOutput.processResourcesProvider.get()
} catch (e: UnknownTaskException) {
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
variantOutput.processResources
}
processResources.dependsOn(copyFlutterAssetsTask)
@ -361,19 +365,26 @@ class FlutterPlugin : Plugin<Project> {
// * `build-mode` can be `release|debug|profile`.
variant.outputs.forEach { output ->
assembleTask.doLast {
output as ApkVariantOutput
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
output as com.android.build.gradle.api.ApkVariantOutput
val packageApplicationProvider: PackageAndroidArtifact =
variant.packageApplicationProvider.get()
val outputDirectory: Directory =
packageApplicationProvider.outputDirectory.get()
val outputDirectoryStr: String = outputDirectory.toString()
var filename = "app"
val abi = output.getFilter(VariantOutput.FilterType.ABI)
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
val abi = output.getFilter(com.android.build.VariantOutput.FilterType.ABI)
if (abi != null && abi.isNotEmpty()) {
filename += "-$abi"
}
if (variant.flavorName != null && variant.flavorName.isNotEmpty()) {
filename += "-${variant.flavorName.toLowerCase()}"
filename += "-${FlutterPluginUtils.lowercase(variant.flavorName)}"
}
filename += "-${FlutterPluginUtils.buildModeFor(variant.buildType)}"
projectToAddTasksTo.copy {
@ -395,13 +406,13 @@ class FlutterPlugin : Plugin<Project> {
// This path is not flavor specific and must only be added once.
// If support for flavors is added to native assets, then they must only be added
// once per flavor; see https://github.com/dart-lang/native/issues/1359.
val nativeAssetsDir: String =
val nativeAssetsDir =
"${projectToAddTasksTo.layout.buildDirectory.get()}/../native_assets/android/jniLibs/lib/"
android.sourceSets
.getByName("main")
.jniLibs
.srcDir(nativeAssetsDir)
getPluginHandler(projectToAddTasksTo!!).configurePlugins(engineVersion!!)
getPluginHandler(projectToAddTasksTo).configurePlugins(engineVersion!!)
FlutterPluginUtils.detectLowCompileSdkVersionOrNdkVersion(
projectToAddTasksTo,
getPluginHandler(projectToAddTasksTo).getPluginList()
@ -469,10 +480,12 @@ class FlutterPlugin : Plugin<Project> {
flutterPlugin,
targetPlatforms
)
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
val mergeAssets =
projectToAddTasksTo
.tasks
.findByPath(":$hostAppProjectName:merge${appProjectVariant.name.capitalize()}Assets")
.findByPath(":$hostAppProjectName:merge${FlutterPluginUtils.capitalize(appProjectVariant.name)}Assets")
check(mergeAssets != null)
mergeAssets.dependsOn(copyFlutterAssetsTask)
}
@ -502,7 +515,7 @@ class FlutterPlugin : Plugin<Project> {
* be sure to change any instances of this string in symbols in the code below
* to match.
*/
const val FLUTTER_BUILD_PREFIX: String = "flutterBuild"
private const val FLUTTER_BUILD_PREFIX: String = "flutterBuild"
/**
* Finds a task by name, returning null if the task does not exist.
@ -517,8 +530,10 @@ class FlutterPlugin : Plugin<Project> {
null
}
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
private fun addFlutterDeps(
variant: BaseVariant,
@Suppress("DEPRECATION") variant: com.android.build.gradle.api.BaseVariant,
flutterPlugin: FlutterPlugin,
targetPlatforms: List<String>
): Task {
@ -559,9 +574,15 @@ class FlutterPlugin : Plugin<Project> {
if (FlutterPluginUtils.shouldProjectSplitPerAbi(project)) {
variant.outputs.forEach { output ->
// need to force this as the API does not return the right thing for our use.
output as ApkVariantOutput
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
output as com.android.build.gradle.api.ApkVariantOutput
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
val filterIdentifier: String =
output.getFilter(VariantOutput.FilterType.ABI)
output.getFilter(com.android.build.VariantOutput.FilterType.ABI)
val abiVersionCode: Int? = FlutterPluginConstants.ABI_VERSION[filterIdentifier]
if (abiVersionCode != null) {
output.versionCodeOverride
@ -647,8 +668,8 @@ class FlutterPlugin : Plugin<Project> {
project.layout.buildDirectory.dir("${FlutterPluginConstants.INTERMEDIATES_DIR}/flutter/${variant.name}/libs.jar")
)
val packJniLibsTaskProvider: TaskProvider<Jar> =
project.tasks.register<Jar>(
"packJniLibs${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}",
project.tasks.register(
"packJniLibs${FLUTTER_BUILD_PREFIX}${FlutterPluginUtils.capitalize(variant.name)}",
Jar::class.java
) {
destinationDirectory.set(libJar.parentFile)
@ -663,9 +684,9 @@ class FlutterPlugin : Plugin<Project> {
}
// Copy the native assets created by build.dart and placed in build/native_assets by flutter assemble.
// The `$project.layout.buildDirectory` is '.android/Flutter/build/' instead of 'build/'.
val buildDir: String =
val buildDir =
"${FlutterPluginUtils.getFlutterSourceDirectory(project)}/build"
val nativeAssetsDir: String =
val nativeAssetsDir =
"$buildDir/native_assets/android/jniLibs/lib"
from("$nativeAssetsDir/$abi") {
include("*.so")
@ -683,13 +704,14 @@ class FlutterPlugin : Plugin<Project> {
)
val copyFlutterAssetsTaskProvider: TaskProvider<Copy> =
project.tasks.register(
"copyFlutterAssets${variant.name.capitalize()}",
"copyFlutterAssets${FlutterPluginUtils.capitalize(variant.name)}",
Copy::class.java
) {
dependsOn(compileTask)
with(compileTask.assets)
// TODO(gmackall): Replace with filePermissions.user.read/write = true once
// minimum supported Gradle version is 8.3.
@Suppress("DEPRECATION")
fileMode = 420 // corresponds to unix 0644 in base 8
if (isUsedAsSubproject) {
// TODO(gmackall): above is always false, can delete
@ -701,20 +723,29 @@ class FlutterPlugin : Plugin<Project> {
try {
variant.mergeAssetsProvider.get()
} catch (e: IllegalStateException) {
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
variant.mergeAssets
}
dependsOn(mergeAssets)
dependsOn("clean${mergeAssets.name.capitalize()}")
mergeAssets.mustRunAfter("clean${mergeAssets.name.capitalize()}")
dependsOn("clean${FlutterPluginUtils.capitalize(mergeAssets.name)}")
mergeAssets.mustRunAfter("clean${FlutterPluginUtils.capitalize(mergeAssets.name)}")
into(mergeAssets.outputDir)
}
val copyFlutterAssetsTask: Task = copyFlutterAssetsTaskProvider.get()
if (!isUsedAsSubproject) {
val variantOutput: BaseVariantOutput = variant.outputs.first()
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
val variantOutput: com.android.build.gradle.api.BaseVariantOutput = variant.outputs.first()
val processResources =
try {
variantOutput.processResourcesProvider.get()
} catch (e: IllegalStateException) {
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
variantOutput.processResources
}
processResources.dependsOn(copyFlutterAssetsTask)
@ -724,9 +755,9 @@ class FlutterPlugin : Plugin<Project> {
// See https://docs.gradle.org/8.1/userguide/validation_problems.html#implicit_dependency.
val tasksToCheck =
listOf(
"compress${variant.name.capitalize()}Assets",
"bundle${variant.name.capitalize()}Aar",
"bundle${variant.name.capitalize()}LocalLintAar"
"compress${FlutterPluginUtils.capitalize(variant.name)}Assets",
"bundle${FlutterPluginUtils.capitalize(variant.name)}Aar",
"bundle${FlutterPluginUtils.capitalize(variant.name)}LocalLintAar"
)
tasksToCheck.forEach { taskTocheck ->
try {

View File

@ -7,9 +7,6 @@ package com.flutter.gradle
// TODO(gmackall): this should be collapsed back into the core FlutterPlugin once the Groovy to
// kotlin conversion is complete.
object FlutterPluginConstants {
// Strings that define project properties
const val PROP_PROCESS_RESOURCES_PROVIDER = "processResourcesProvider"
/** The platforms that can be passed to the `--Ptarget-platform` flag. */
private const val PLATFORM_ARM32 = "android-arm"
private const val PLATFORM_ARM64 = "android-arm64"
@ -41,7 +38,7 @@ object FlutterPluginConstants {
* Otherwise, the Play Store will complain that the APK variants have the same version.
*/
@JvmStatic val ABI_VERSION =
mapOf<String, Int>(
mapOf(
ARCH_ARM32 to 1,
ARCH_ARM64 to 2,
ARCH_X86 to 3,

View File

@ -6,14 +6,11 @@ package com.flutter.gradle
import com.android.build.gradle.AbstractAppExtension
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.api.ApplicationVariant
import com.android.build.gradle.api.BaseVariantOutput
import com.android.build.gradle.tasks.ProcessAndroidResources
import com.android.builder.model.BuildType
import com.flutter.gradle.plugins.PluginHandler
import groovy.lang.Closure
import groovy.util.Node
import groovy.util.XmlParser
import org.gradle.api.GradleException
import org.gradle.api.JavaVersion
import org.gradle.api.Project
@ -62,6 +59,13 @@ object FlutterPluginUtils {
@Suppress("DEPRECATION")
internal fun capitalize(string: String): String = string.capitalize()
// Kotlin's toLowerCase function is deprecated, but the suggested replacement is not supported
// by the minimum version of Kotlin that we support. Centralize the use to one place, so that
// when our minimum version does support the replacement we can replace by changing a single
// line.
@Suppress("DEPRECATION")
internal fun lowercase(string: String): String = string.toLowerCase()
// compareTo implementation of version strings in the format of ints and periods
// Will not crash on RC candidate strings but considers all RC candidates the same version.
// Returns -1 if firstString < secondString, 0 if firstString == secondString, 1 if firstString > secondString
@ -513,11 +517,8 @@ object FlutterPluginUtils {
getCompileSdkFromProject(project).toIntOrNull() ?: Int.MAX_VALUE
var maxPluginCompileSdkVersion = projectCompileSdkVersion
// TODO(gmackall): This should be updated to reflect newer templates.
// The default for AGP 4.1.0 used in old templates.
val ndkVersionIfUnspecified = "21.1.6352462"
val projectNdkVersion =
getAndroidExtension(project).ndkVersion ?: ndkVersionIfUnspecified
getAndroidExtension(project).ndkVersion
var maxPluginNdkVersion = projectNdkVersion
var numProcessedPlugins = pluginList.size
val pluginsWithHigherSdkVersion = mutableListOf<PluginVersionPair>()
@ -543,14 +544,19 @@ object FlutterPluginUtils {
)
}
val pluginNdkVersion: String =
getAndroidExtension(pluginProject).ndkVersion ?: ndkVersionIfUnspecified
getAndroidExtension(pluginProject).ndkVersion
maxPluginNdkVersion =
VersionUtils.mostRecentSemanticVersion(
pluginNdkVersion,
maxPluginNdkVersion
)
if (pluginNdkVersion != projectNdkVersion) {
pluginsWithDifferentNdkVersion.add(PluginVersionPair(pluginName, pluginNdkVersion))
pluginsWithDifferentNdkVersion.add(
PluginVersionPair(
pluginName,
pluginNdkVersion
)
)
}
numProcessedPlugins--
@ -614,7 +620,7 @@ object FlutterPluginUtils {
// and rebuilt when running clean builds.
gradleProjectAndroidExtension.externalNativeBuild.cmake.buildStagingDirectory(
gradleProject.layout.buildDirectory
.dir("${FlutterPluginConstants.INTERMEDIATES_DIR}/flutter/.cxx")
.dir("../.cxx")
.get()
.asFile.path
)
@ -734,7 +740,10 @@ object FlutterPluginUtils {
}
}
private fun findProcessResources(baseVariantOutput: BaseVariantOutput): ProcessAndroidResources =
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
private fun findProcessResources(baseVariantOutput: com.android.build.gradle.api.BaseVariantOutput): ProcessAndroidResources =
baseVariantOutput.processResourcesProvider?.get() ?: baseVariantOutput.processResources
/**
@ -769,12 +778,15 @@ object FlutterPluginUtils {
}
android.applicationVariants.configureEach {
val variant = this
project.tasks.register("output${FlutterPluginUtils.capitalize(variant.name)}AppLinkSettings") {
project.tasks.register("output${capitalize(variant.name)}AppLinkSettings") {
val task: Task = this
task.description =
"stores app links settings for the given build variant of this Android project into a json file."
variant.outputs.configureEach {
val baseVariantOutput: BaseVariantOutput = this
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
val baseVariantOutput: com.android.build.gradle.api.BaseVariantOutput = this
// Deeplinks are defined in AndroidManifest.xml and is only available after
// processResourcesProvider.
dependsOn(findProcessResources(baseVariantOutput))
@ -800,18 +812,21 @@ object FlutterPluginUtils {
* @param BaseVariantOutput The output of a specific build variant (e.g., debug, release).
* @param variant The application variant being processed.
*/
@Suppress("KDocUnresolvedReference")
private fun createAppLinkSettings(
variant: ApplicationVariant,
baseVariantOutput: BaseVariantOutput
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION") variant: com.android.build.gradle.api.ApplicationVariant,
@Suppress("DEPRECATION") baseVariantOutput: com.android.build.gradle.api.BaseVariantOutput
): AppLinkSettings {
val appLinkSettings = AppLinkSettings(variant.applicationId)
// TODO https://github.com/flutter/flutter/issues/165881
// Use import groovy.xml.XmlParser instead.
// XmlParser is not namespace aware because it makes querying nodes cumbersome.
// TODO(gmackall): Migrate to AGPs variant api.
// https://github.com/flutter/flutter/issues/166550
@Suppress("DEPRECATION")
val manifest: Node =
XmlParser(false, false).parse(findProcessResources(baseVariantOutput).manifestFile)
// The groovy.xml.XmlParser import would use getProperty like
// manifest.getProperty("application").let { applicationNode -> ...
groovy.xml.XmlParser(false, false).parse(findProcessResources(baseVariantOutput).manifestFile)
val applicationNode: Node? =
manifest.children().find { node ->
node is Node && node.name() == "application"

View File

@ -26,7 +26,7 @@ object VersionUtils {
val v2Parts = version2.split(".", "-")
val maxSize = max(v1Parts.size, v2Parts.size)
for (i in 0..maxSize - 1) {
for (i in 0 until maxSize) {
val v1Part: String = v1Parts.getOrNull(i) ?: "0"
val v2Part: String = v2Parts.getOrNull(i) ?: "0"
@ -42,7 +42,7 @@ object VersionUtils {
return version1 // v1 is a number, v2 is not, so v1 is newer.
v1Num == null && v2Num != null ->
return version2 // v1 is not a number, v2 is, so v2 is newer.
v1Num == null && v2Num == null -> { // Both are not numbers (pre-release identifiers)
else -> { // Both are not numbers (pre-release identifiers)
if (v1Part != v2Part) {
return if (comparePreReleaseIdentifiers(v1Part, v2Part)) version1 else version2
}

View File

@ -94,7 +94,7 @@ class PluginHandler(
* This is only possible by taking all plugins into account, which
* only appear on the `dependencyGraph` and in the `.flutter-plugins` file.
* So in summary the plugins are currently selected from the `dependencyGraph`
* and filtered then with the [doesSupportAndroidPlatform] method instead of
* and filtered then with the [pluginSupportsAndroidPlatform] method instead of
* just using the `plugins.android` list.
*/
private fun configureLegacyPluginEachProjects(engineVersionValue: String) {

View File

@ -132,7 +132,7 @@ open class BaseFlutterTask : DefaultTask() {
var flavor: String? = null
/**
* Gets the dependency file(s) by calling [com.flutter.gradle.BaseFlutterTaskHelper.getDependenciesFiles].
* Gets the dependency file(s) by calling [com.flutter.gradle.tasks.BaseFlutterTaskHelper.getDependenciesFiles].
*
* @return the dependency file(s) based on the current intermediate directory path.
*/

View File

@ -10,6 +10,8 @@ import org.gradle.api.GradleException
import org.gradle.api.file.FileCollection
import org.gradle.api.logging.LogLevel
import org.gradle.api.tasks.OutputFiles
import org.gradle.kotlin.dsl.support.serviceOf
import org.gradle.process.ExecOperations
import org.gradle.process.ExecSpec
import java.nio.file.Paths
@ -72,6 +74,7 @@ object BaseFlutterTaskHelper {
.map {
"android_aot_deferred_components_bundle_${baseFlutterTask.buildMode}_$it"
}
else -> baseFlutterTask.targetPlatformValues!!.map { "android_aot_bundle_${baseFlutterTask.buildMode}_$it" }
}
return ruleNames
@ -111,7 +114,17 @@ object BaseFlutterTaskHelper {
if (!baseFlutterTask.fastStart!! || baseFlutterTask.buildMode != "debug") {
args("-dTargetFile=${baseFlutterTask.targetPath}")
} else {
args("-dTargetFile=${Paths.get(baseFlutterTask.flutterRoot!!.absolutePath, "examples", "splash", "lib", "main.dart")}")
args(
"-dTargetFile=${
Paths.get(
baseFlutterTask.flutterRoot!!.absolutePath,
"examples",
"splash",
"lib",
"main.dart"
)
}"
)
}
args("-dTargetPlatform=android")
args("-dBuildMode=${baseFlutterTask.buildMode}")
@ -157,6 +170,7 @@ object BaseFlutterTaskHelper {
fun buildBundle(baseFlutterTask: BaseFlutterTask) {
checkPreConditions(baseFlutterTask)
baseFlutterTask.logging.captureStandardError(LogLevel.ERROR)
baseFlutterTask.project.exec(createExecSpecActionFromTask(baseFlutterTask = baseFlutterTask))
val execOps = baseFlutterTask.project.serviceOf<ExecOperations>()
execOps.exec(createExecSpecActionFromTask(baseFlutterTask = baseFlutterTask))
}
}

View File

@ -59,7 +59,10 @@ class NativePluginLoader {
// of a federated plugin).
val needsBuild = androidPlugin[NATIVE_BUILD_KEY] as? Boolean ?: true
if (needsBuild) {
nativePlugins.add(androidPlugin as Map<String, Any>) // Safe cast when adding, assuming type is now validated
// Suppress the unchecked cast warning as we define the structure of the JSON in
// the tool and we have already mostly validated the structure.
@Suppress("UNCHECKED_CAST")
nativePlugins.add(androidPlugin as Map<String, Any>)
}
}
return nativePlugins.toList() // Return immutable list
@ -136,6 +139,9 @@ class NativePluginLoader {
if (pluginsDependencyFile.exists()) {
val slurper = JsonSlurper()
val readText = slurper.parseText(pluginsDependencyFile.readText())
// Suppress the unchecked cast warning as we define the structure of the JSON in the tool.
@Suppress("UNCHECKED_CAST")
val parsedText =
readText as? Map<String, Any>
?: error("Parsed JSON is not a Map<String, Any>: $readText")

View File

@ -13,6 +13,8 @@ import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.logging.LoggingManager
import org.gradle.kotlin.dsl.support.serviceOf
import org.gradle.process.ExecOperations
import org.gradle.process.ExecSpec
import org.gradle.process.ProcessForkOptions
import org.junit.jupiter.api.assertDoesNotThrow
@ -544,7 +546,9 @@ class BaseFlutterTaskHelperTest {
val baseFlutterTask = mockk<BaseFlutterTask>()
val mockLoggingManager = mockk<LoggingManager>()
val mockFile = mockk<File>()
val mockProject = mockk<Project>()
// Mocking the serviceOf() extension below requires us to specify this internal type
// unfortunately.
val mockProject = mockk<org.gradle.api.internal.project.ProjectInternal>()
// When baseFlutterTask.sourceDir is null, an exception is thrown. We mock its return value
// before creating a BaseFlutterTaskHelper object.
@ -554,7 +558,11 @@ class BaseFlutterTaskHelperTest {
every { baseFlutterTask.logging } returns mockLoggingManager
every { mockLoggingManager.captureStandardError(any()) } returns mockLoggingManager
every { baseFlutterTask.project } returns mockProject
every { mockProject.exec(any<Action<ExecSpec>>()) } returns mockk()
val mockExecOperations = mockk<ExecOperations>()
every {
mockProject.serviceOf<ExecOperations>()
} returns mockExecOperations
every { mockExecOperations.exec(any<Action<ExecSpec>>()) } returns mockk()
BaseFlutterTaskHelper.buildBundle(baseFlutterTask)
}