diff --git a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt index eab97a883626b..8715dc64d4642 100644 --- a/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt +++ b/packages/flutter_tools/gradle/src/main/kotlin/FlutterPlugin.kt @@ -8,6 +8,7 @@ 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.ApkVariant import com.android.build.gradle.tasks.PackageAndroidArtifact import com.android.build.gradle.tasks.ProcessAndroidResources import com.flutter.gradle.FlutterPluginUtils.readPropertiesIfExist @@ -620,6 +621,8 @@ class FlutterPlugin : Plugin { // https://github.com/flutter/flutter/issues/166550 @Suppress("DEPRECATION") output as com.android.build.gradle.api.ApkVariantOutput + val versionCodeIfPresent: Int? = if (variant is ApkVariant) variant.versionCode else null + // TODO(gmackall): Migrate to AGPs variant api. // https://github.com/flutter/flutter/issues/166550 @Suppress("DEPRECATION") @@ -627,7 +630,10 @@ class FlutterPlugin : Plugin { output.getFilter(com.android.build.VariantOutput.FilterType.ABI) val abiVersionCode: Int? = FlutterPluginConstants.ABI_VERSION[filterIdentifier] if (abiVersionCode != null) { - output.versionCodeOverride = abiVersionCode * 1000 + variant.mergedFlavor.versionCode as Int + output.versionCodeOverride = abiVersionCode * 1000 + ( + versionCodeIfPresent + ?: variant.mergedFlavor.versionCode as Int + ) } } } diff --git a/packages/flutter_tools/test/integration.shard/flutter_build_apk_split_per_abi_test.dart b/packages/flutter_tools/test/integration.shard/flutter_build_apk_split_per_abi_test.dart index ae17f5fa7f9ed..724ce4daf9e10 100644 --- a/packages/flutter_tools/test/integration.shard/flutter_build_apk_split_per_abi_test.dart +++ b/packages/flutter_tools/test/integration.shard/flutter_build_apk_split_per_abi_test.dart @@ -14,9 +14,90 @@ import 'test_utils.dart'; /// ABI → index map (same as FlutterPluginConstants.ABI_VERSION) const _abiIndexMap = {'armeabi-v7a': 1, 'arm64-v8a': 2, 'x86_64': 4}; +const _appGradleWithVersionCodeModification = r''' +import com.android.build.api.variant.FilterConfiguration.FilterType.* +import java.util.Properties +import java.io.FileInputStream + +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.splitperabi" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.splitperabi" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} + +val abiCodes = mapOf("x86_64" to 1, "armeabi-v7a" to 2, "arm64-v8a" to 3, "universal" to 4) + +androidComponents { + onVariants { variant -> + + variant.outputs.forEach { output -> + val name = output.filters.find { it.filterType == ABI }?.identifier + + val baseAbiCode = abiCodes[name ?: "universal"] + if (baseAbiCode != null) { + output.versionCode.set(output.versionCode.get() * 10000) + } + } + } +} + +'''; + // Check that `flutter build apk --split-per-abi` generates a versionCode equal to abiIndex * 1000 + buildNumber -Future _assertSplitPerAbiVersionCodes(int? buildNumber) async { - final String workingDirectory = fileSystem.path.join(getFlutterRoot(), 'examples', 'hello_world'); +Future _assertSplitPerAbiVersionCodes( + int? buildNumber, + Directory workingDirectory, + bool usingCustomAppGradleFile, +) async { + if (usingCustomAppGradleFile) { + // Replace the app level build.gradle with one that modifies the version code. + final File appBuildGradle = fileSystem + .directory(workingDirectory) + .childDirectory('android') + .childDirectory('app') + .childFile('build.gradle.kts'); + + await appBuildGradle.writeAsString(_appGradleWithVersionCodeModification); + } final args = [ flutterBin, @@ -31,7 +112,10 @@ Future _assertSplitPerAbiVersionCodes(int? buildNumber) async { args.addAll(['--build-number', buildNumber.toString()]); } - final ProcessResult result = processManager.runSync(args, workingDirectory: workingDirectory); + final ProcessResult result = processManager.runSync( + args, + workingDirectory: workingDirectory.path, + ); expect( result.exitCode, 0, @@ -92,7 +176,8 @@ Future _assertSplitPerAbiVersionCodes(int? buildNumber) async { ); final int actual = actualVersionCodes[abi]!; - final int expected = (abiIndex * 1000) + (buildNumber ?? 1); + final int expected = + (abiIndex * 1000) + ((buildNumber ?? 1) * (usingCustomAppGradleFile ? 10000 : 1)); expect( actual, expected, @@ -105,11 +190,30 @@ Future _assertSplitPerAbiVersionCodes(int? buildNumber) async { } void main() { + late Directory tempDir; + late Directory appDir; + setUp(() async { + tempDir = createResolvedTempDirectorySync('flutter_split_per_abi_test.'); + + processManager.runSync([ + flutterBin, + ...getLocalEngineArguments(), + 'create', + '--platforms=android', + 'splitperabi', + ], workingDirectory: tempDir.path); + appDir = tempDir.childDirectory('splitperabi'); + }); + + tearDown(() async { + tryToDelete(tempDir); + }); + // Check with no build-number testWithoutContext( 'APK versionCodes after --split-per-abi (no explicit build-number) follow "(abiIndex * 1000) + 1"', () async { - await _assertSplitPerAbiVersionCodes(null); + await _assertSplitPerAbiVersionCodes(null, appDir, false); }, ); @@ -117,7 +221,15 @@ void main() { testWithoutContext( 'APK versionCodes after --split-per-abi with custom build-number=42 follow "(abiIndex * 1000) + 42"', () async { - await _assertSplitPerAbiVersionCodes(42); + await _assertSplitPerAbiVersionCodes(42, appDir, false); + }, + ); + + // Check with custom buildNumber=42 and custom gradle file which multiplies build number by 10000 + testWithoutContext( + 'APK versionCodes after --split-per-abi with custom build-number=42 and gradle file follow "(abiIndex * 1000) + (42 * 10000)"', + () async { + await _assertSplitPerAbiVersionCodes(42, appDir, true); }, ); }