diff --git a/dev/devicelab/bin/tasks/gradle_plugin_fat_apk_test.dart b/dev/devicelab/bin/tasks/gradle_plugin_fat_apk_test.dart index b0cf6dd7e9..81e0da65e0 100644 --- a/dev/devicelab/bin/tasks/gradle_plugin_fat_apk_test.dart +++ b/dev/devicelab/bin/tasks/gradle_plugin_fat_apk_test.dart @@ -157,14 +157,7 @@ Future 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'); } diff --git a/packages/flutter_tools/gradle/build.gradle.kts b/packages/flutter_tools/gradle/build.gradle.kts index 0797f58275..d2a23ecfd4 100644 --- a/packages/flutter_tools/gradle/build.gradle.kts +++ b/packages/flutter_tools/gradle/build.gradle.kts @@ -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 { - dependsOn(tasks.compileKotlin) - classpath += files(tasks.compileKotlin.get().destinationDirectory) -} - -tasks.classes { - dependsOn(tasks.compileGroovy) -} - gradlePlugin { plugins { // The "flutterPlugin" name isn't used anywhere. diff --git a/packages/flutter_tools/gradle/src/main/kotlin/Deeplink.kt b/packages/flutter_tools/gradle/src/main/kotlin/Deeplink.kt index ead9c47d2a..d7eccebcab 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/Deeplink.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/Deeplink.kt @@ -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. diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterAppPluginLoaderPlugin.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterAppPluginLoaderPlugin.kt index 2ebfb9ee89..081968af5a 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterAppPluginLoaderPlugin.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterAppPluginLoaderPlugin.kt @@ -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 { override fun apply(settings: Settings) { val flutterProjectRoot: File = settings.settingsDir.parentFile diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterExtension.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterExtension.kt index 7f41f08ad2..2bcfce6eda 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterExtension.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterExtension.kt @@ -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 diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt index d7b81902d2..b3d2a6ec6e 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt @@ -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 { 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 { 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 { 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 { rootProject.subprojects.forEach { subproject -> val gradlew: String = getExecutableNameForPlatform("${rootProject.projectDir}/gradlew") - rootProject.exec { + val execOps = rootProject.serviceOf() + execOps.exec { workingDir(rootProject.projectDir) executable(gradlew) args(":${subproject.name}:dependencies", "--write-locks") @@ -342,11 +339,18 @@ class FlutterPlugin : Plugin { } 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 { // * `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 { // 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 { 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 { * 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 { 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 ): Task { @@ -559,9 +574,15 @@ class FlutterPlugin : Plugin { 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.layout.buildDirectory.dir("${FlutterPluginConstants.INTERMEDIATES_DIR}/flutter/${variant.name}/libs.jar") ) val packJniLibsTaskProvider: TaskProvider = - project.tasks.register( - "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 { } // 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 { ) val copyFlutterAssetsTaskProvider: TaskProvider = 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 { 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 { // 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 { diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginConstants.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginConstants.kt index 8f8c0bda56..c49cfe356e 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginConstants.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginConstants.kt @@ -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( + mapOf( ARCH_ARM32 to 1, ARCH_ARM64 to 2, ARCH_X86 to 3, diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt index fc1fd7a454..2b622591eb 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt @@ -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() @@ -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" diff --git a/packages/flutter_tools/gradle/src/main/kotlin/VersionUtils.kt b/packages/flutter_tools/gradle/src/main/kotlin/VersionUtils.kt index 8f00e7ac8e..96a0923419 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/VersionUtils.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/VersionUtils.kt @@ -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 } diff --git a/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt b/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt index b452435200..23cbcc5468 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt @@ -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) { diff --git a/packages/flutter_tools/gradle/src/main/kotlin/tasks/BaseFlutterTask.kt b/packages/flutter_tools/gradle/src/main/kotlin/tasks/BaseFlutterTask.kt index cb9d45d892..6147809ea6 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/tasks/BaseFlutterTask.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/tasks/BaseFlutterTask.kt @@ -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. */ diff --git a/packages/flutter_tools/gradle/src/main/kotlin/tasks/BaseFlutterTaskHelper.kt b/packages/flutter_tools/gradle/src/main/kotlin/tasks/BaseFlutterTaskHelper.kt index bfb0bcc5d3..edbfd888d0 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/tasks/BaseFlutterTaskHelper.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/tasks/BaseFlutterTaskHelper.kt @@ -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() + execOps.exec(createExecSpecActionFromTask(baseFlutterTask = baseFlutterTask)) } } diff --git a/packages/flutter_tools/gradle/src/main/scripts/native_plugin_loader.gradle.kts b/packages/flutter_tools/gradle/src/main/scripts/native_plugin_loader.gradle.kts index eab9482ed4..60753ee2f0 100644 --- a/packages/flutter_tools/gradle/src/main/scripts/native_plugin_loader.gradle.kts +++ b/packages/flutter_tools/gradle/src/main/scripts/native_plugin_loader.gradle.kts @@ -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) // 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) } } 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 ?: error("Parsed JSON is not a Map: $readText") diff --git a/packages/flutter_tools/gradle/src/test/kotlin/tasks/BaseFlutterTaskHelperTest.kt b/packages/flutter_tools/gradle/src/test/kotlin/tasks/BaseFlutterTaskHelperTest.kt index 92565f11d6..88cca3d0fd 100644 --- a/packages/flutter_tools/gradle/src/test/kotlin/tasks/BaseFlutterTaskHelperTest.kt +++ b/packages/flutter_tools/gradle/src/test/kotlin/tasks/BaseFlutterTaskHelperTest.kt @@ -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() val mockLoggingManager = mockk() val mockFile = mockk() - val mockProject = mockk() + // Mocking the serviceOf() extension below requires us to specify this internal type + // unfortunately. + val mockProject = mockk() // 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>()) } returns mockk() + val mockExecOperations = mockk() + every { + mockProject.serviceOf() + } returns mockExecOperations + every { mockExecOperations.exec(any>()) } returns mockk() BaseFlutterTaskHelper.buildBundle(baseFlutterTask) }