Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ Future<TaskResult> buildFlutterApkWithSpecifiedDependencyVersions({
section('Add a dependency on a plugin');
await flutter(
'pub',
options: <String>['add', 'shared_preferences_android:2.4.7'], // Chosen randomly.
options: <String>[
'add',
'shared_preferences_android:2.4.24',
], // Smallest version jump supporting AGP 9.
workingDirectory: appPath,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,23 @@ tasks.register("embedTestResultImages") {
val packageId = "com.example.android_hardware_smoke_test"
val discoveredTests = mutableListOf<DiscoveredTest>()

// Resolve binary safe adb executable from Android Gradle Plugin BaseExtension
val android = project.extensions.getByType(com.android.build.gradle.BaseExtension::class.java)
val adbPath = android.adbExecutable.absolutePath
// Resolve binary-safe adb executable from Android Gradle Plugin (new variant API with BaseExtension fallback)
val adbPath =
try {
val androidComponents =
project.extensions.getByType(
com.android.build.api.variant.ApplicationAndroidComponentsExtension::class.java
)
androidComponents.sdkComponents.adb
.get()
.asFile.absolutePath
} catch (_: org.gradle.api.UnknownDomainObjectException) {
val android = project.extensions.getByType(com.android.build.gradle.BaseExtension::class.java)
android.adbExecutable.absolutePath
} catch (_: IllegalArgumentException) {
val android = project.extensions.getByType(com.android.build.gradle.BaseExtension::class.java)
android.adbExecutable.absolutePath
}
println("Resolved binary-safe adb executable from AGP: $adbPath")

// 1. Query the device sandbox to list all files in cache/results/ using ProcessBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,15 @@ projects. That opt-out dies with AGP 10.
`outputs/flutter-apk` directory, because a shared `@OutputDirectory` would overlap
between variants by construction. A runtime warning reports produced names outside
the predicted set.
6. **P3 pre-spike (afterEvaluate DSL mutation under newDsl).** The planned scratch-app
6. **Stable-channel add-migrator guard (release management, not in this repo's
changes).** The stable channel still carries the old `DisableNewDslMigration`,
which ADDS `android.newDsl=false`. Once the P9 removal migrator reaches a
channel, switching between that channel and stable would flip-flop
gradle.properties. Before P9 is released, cherry-pick a guard onto the
stable-side add-migrator (skip adding the opt-out when the project's recorded
Flutter/AGP versions indicate the new-DSL-capable plugin) or accept the
flip-flop for the overlap window and document it in the release notes.
7. **P3 pre-spike (afterEvaluate DSL mutation under newDsl).** The planned scratch-app
spike (AGP 9.1 + `newDsl=true` + custom build type, verifying that build-type
creation from `pluginProject.afterEvaluate` still works) could not run in the
implementation sandbox (no AGP artifact access). The `initWith` copy landed on the
Expand Down
7 changes: 6 additions & 1 deletion docs/platforms/android/website-page-draft.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
*Draft breaking-change page for `docs.flutter.dev/release/breaking-changes/`.
This file is the source of truth until the page is published to
flutter/website; publishing must complete before the newDsl flip reaches the
beta channel. Contributor-facing details live in
beta channel. The page MUST be published at
`https://docs.flutter.dev/release/breaking-changes/android-agp-new-dsl` —
that URL is hard-coded as `kNewDslBreakingChangeDocsUrl` in
`packages/flutter_tools/lib/src/android/gradle_errors.dart` and is printed by
the legacy-variant-API error handler and the opt-out removal migrator.
Contributor-facing details live in
[Migrating-Flutter-Gradle-Plugin-to-AGP-public-API.md](Migrating-Flutter-Gradle-Plugin-to-AGP-public-API.md).*

## Summary
Expand Down
4 changes: 2 additions & 2 deletions packages/flutter_tools/lib/src/android/gradle.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ import 'java.dart';
import 'migrations/android_studio_java_gradle_conflict_migration.dart';
import 'migrations/cmake_android_16k_pages_migration.dart';
import 'migrations/disable_built_in_kotlin_migration.dart';
import 'migrations/disable_new_dsl_migration.dart';
import 'migrations/min_sdk_version_migration.dart';
import 'migrations/multidex_removal_migration.dart';
import 'migrations/remove_new_dsl_opt_out_migration.dart';
import 'migrations/top_level_gradle_build_file_migration.dart';

/// The regex to grab variant names from printBuildVariants gradle task
Expand Down Expand Up @@ -518,7 +518,7 @@ To fix this, you can either:
MultidexRemovalMigration(project.android, _logger),
CmakeAndroid16kPagesMigration(project.android, _logger),
DisableBuiltInKotlinMigration(project.android, _logger),
DisableNewDslMigration(project.android, _logger),
RemoveNewDslOptOutMigration(project.android, _logger),
];

final migration = ProjectMigration(migrators);
Expand Down
39 changes: 22 additions & 17 deletions packages/flutter_tools/lib/src/android/gradle_errors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ final gradleErrors = <GradleHandledError>[
jlinkErrorWithJava21AndSourceCompatibility,
missingNdkSourcePropertiesFile,
applyingKotlinAndroidPluginErrorHandler,
useNewAgpDslErrorHandler,
legacyVariantApiUsageErrorHandler,
incompatibleKotlinVersionHandler, // This handler should always be last, as its key log output is sometimes in error messages with other root causes.
];

Expand Down Expand Up @@ -689,9 +689,11 @@ final missingNdkSourcePropertiesFile = GradleHandledError(
const String kMigrateToBuiltInKotlinDocsUrl =
'https://docs.flutter.dev/release/breaking-changes/migrate-to-built-in-kotlin';

/// The URL for documentation on opting out of the new AGP DSL.
const String kOptOutOfNewDslDocsUrl =
'https://developer.android.com/build/releases/agp-9-0-0-release-notes';
/// The URL for the breaking-change page covering the Android Gradle Plugin new-DSL
/// migration (legacy variant API removal), including before/after recipes and the
/// temporary `android.newDsl=false` escape hatch.
const String kNewDslBreakingChangeDocsUrl =
'https://docs.flutter.dev/release/breaking-changes/android-agp-new-dsl';

/// Handler when applying the kotlin-android plugin results in a build failure. This failure occurs when
/// using AGP 9+ because built-in Kotlin has become the default behavior.
Expand All @@ -715,29 +717,32 @@ To resolve this, migrate to built-in Kotlin.
eventLabel: 'applying-kotlin-android-plugin-error',
);

/// Handler when using the new AGP DSL interfaces. Starting AGP 9+, only the new
/// DSL interfaces are used. This results in a failure because we still depend
/// on old DSL types.
/// Handler for Gradle build scripts that use the removed legacy AGP variant API
/// (`applicationVariants`, `libraryVariants`, `variantFilter`). Flutter projects build
/// with the Android Gradle Plugin's new DSL, under which these APIs do not exist.
@visibleForTesting
final useNewAgpDslErrorHandler = GradleHandledError(
final legacyVariantApiUsageErrorHandler = GradleHandledError(
test: _lineMatcher(const <String>[
"> Failed to apply plugin 'dev.flutter.flutter-gradle-plugin'",
'> java.lang.NullPointerException (no error message)',
"Could not get unknown property 'applicationVariants'",
"Could not get unknown property 'libraryVariants'",
"Could not get unknown property 'testVariants'",
"Could not get unknown property 'variantFilter'",
'Could not find method applicationVariants(',
'Could not find method libraryVariants(',
'Could not find method variantFilter(',
]),
handler:
({required String line, required FlutterProject project, required bool usesAndroidX}) async {
final File appGradleFile = project.android.appGradleFile;
globals.printBox(
'''
${globals.logger.terminal.warningMark} Starting AGP 9+, only the new DSL interface will be read.
This results in a build failure when applying the Flutter Gradle plugin at ${appGradleFile.path}.
\nTo resolve this update flutter or opt out of `android.newDsl`.
For instructions on how to opt out, see: $kOptOutOfNewDslDocsUrl
\nIf you are not upgrading to AGP 9+, run `flutter analyze --suggestions` to check for incompatible dependencies.''',
${globals.logger.terminal.warningMark} A Gradle build script in this project uses the Android Gradle Plugin's legacy variant API (for example `android.applicationVariants`), which does not exist under the new Android Gradle Plugin DSL that Flutter projects now build with.
\nTo resolve this, migrate the build script to the variant API (`androidComponents.onVariants`).
For before/after examples of common patterns, see: $kNewDslBreakingChangeDocsUrl
\nAs a temporary escape hatch, you can add `android.newDsl=false` to android/gradle.properties, but this stops working with Android Gradle Plugin 10, which removes the legacy API entirely.''',
title: _boxTitle,
);

return GradleBuildStatus.exit;
},
eventLabel: 'use-new-agp-dsl-error',
eventLabel: 'legacy-variant-api-usage',
);
2 changes: 2 additions & 0 deletions packages/flutter_tools/lib/src/android/gradle_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ const templateAndroidGradlePluginVersionForModule = '9.1.0';
// * KGP jvm constant in packages/flutter_tools/gradle/src/test/kotlin/DependencyVersionCheckerTest.kt
// See https://kotlinlang.org/docs/releases.html#release-details
const templateKotlinGradlePluginVersion = '2.4.0';
const templateJunitJupiterEngineVersion = '5.10.2';
const templateJunitPlatformLauncherVersion = '1.10.2';

// The Flutter Gradle Plugin is only applied to app projects, and modules that
// are built from source using (`include_flutter.groovy`). The remaining
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import '../../base/file_system.dart';
import '../../base/project_migrator.dart';
import '../../project.dart';
import '../gradle_errors.dart';

/// The marker comment the project templates placed above the opt-out.
const String _templateMarkerComment = '# This newDsl flag was added by the Flutter template';

/// The marker comment [the former DisableNewDslMigration] placed above the opt-out.
const String _migratorMarkerComment =
'# This newDsl flag was added automatically by Flutter migrator';

/// Matches the opt-out line Flutter wrote (tolerating whitespace and the `:` separator).
/// Deliberately does NOT match `android.newDsl=true` or other values: if the developer
/// edited the line, it is theirs now and stays.
final RegExp _newDslOptOutPattern = RegExp(r'^\s*android\.newDsl\s*[=:]\s*false\s*$');

/// Removes the `android.newDsl=false` opt-out that Flutter previously added to
/// `gradle.properties` (through the project templates and through the former
/// `DisableNewDslMigration`), now that the Flutter Gradle Plugin supports the Android
/// Gradle Plugin's new DSL.
///
/// Only line pairs Flutter wrote are removed: one of the two known marker comments
/// immediately followed by the `android.newDsl=false` property line. The removal is
/// anchored on the `android.newDsl` property line - never on marker wording alone -
/// so the adjacent `android.builtInKotlin` marker/flag lines (owned by the separate
/// built-in Kotlin migration) and hand-added opt-outs are never touched.
class RemoveNewDslOptOutMigration extends ProjectMigrator {
RemoveNewDslOptOutMigration(AndroidProject project, super.logger)
: _gradlePropertiesFile = project.hostAppGradleRoot.childFile('gradle.properties');

final File _gradlePropertiesFile;

@override
Future<void> migrate() async {
if (!_gradlePropertiesFile.existsSync()) {
// Nothing to remove. (The former DisableNewDslMigration created this file when it
// was missing, writing only the marker and the flag; that case is handled by the
// pair removal below, leaving an empty file.)
return;
}
processFileLines(_gradlePropertiesFile);
}

@override
String migrateFileContents(String fileContents) {
final List<String> lines = fileContents.split('\n');
final result = <String>[];
var removed = false;
for (var i = 0; i < lines.length; i++) {
final String trimmed = lines[i].trim();
final bool isFlutterMarker =
trimmed == _templateMarkerComment || trimmed == _migratorMarkerComment;
if (isFlutterMarker && i + 1 < lines.length && _newDslOptOutPattern.hasMatch(lines[i + 1])) {
// Skip the marker comment and the opt-out line it annotates.
i++;
removed = true;
continue;
}
result.add(lines[i]);
}
if (!removed) {
return fileContents;
}
logger.printStatus(
'Removed the android.newDsl opt-out that Flutter previously added to '
'${_gradlePropertiesFile.path}; Android builds now use the Android Gradle '
"Plugin's new DSL. If your Android build fails after this change, see "
'$kNewDslBreakingChangeDocsUrl',
);
return result.join('\n');
}
}
2 changes: 2 additions & 0 deletions packages/flutter_tools/lib/src/commands/create_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,8 @@ mixin CreateBase on FlutterCommand {
'agpVersion': agpVersion,
'agpVersionForModule': gradle.templateAndroidGradlePluginVersionForModule,
'kotlinVersion': kotlinVersion,
'junitJupiterEngineVersion': gradle.templateJunitJupiterEngineVersion,
'junitPlatformLauncherVersion': gradle.templateJunitPlatformLauncherVersion,
'gradleVersion': gradleVersion,
'compileSdkVersion': gradle.compileSdkVersion,
'minSdkVersion': gradle.minSdkVersion,
Expand Down
2 changes: 2 additions & 0 deletions packages/flutter_tools/lib/src/project.dart
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,8 @@ See the link below for more information:
'agpVersion': gradle.templateAndroidGradlePluginVersion,
'agpVersionForModule': gradle.templateAndroidGradlePluginVersionForModule,
'kotlinVersion': gradle.templateKotlinGradlePluginVersion,
'junitJupiterEngineVersion': gradle.templateJunitJupiterEngineVersion,
'junitPlatformLauncherVersion': gradle.templateJunitPlatformLauncherVersion,
'gradleVersion': gradle.templateDefaultGradleVersion,
'compileSdkVersion': gradle.compileSdkVersion,
'minSdkVersion': gradle.minSdkVersion,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
# This newDsl flag was added by the Flutter template
android.newDsl=false
# This builtInKotlin flag was added by the Flutter template
android.builtInKotlin=false
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
# This newDsl flag was added by the Flutter template
android.newDsl=false
# This builtInKotlin flag was added by the Flutter template
android.builtInKotlin=false
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ kotlin {
}

dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.jetbrains.kotlin:kotlin-test:{{kotlinVersion}}")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5:{{kotlinVersion}}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:{{junitJupiterEngineVersion}}")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:{{junitPlatformLauncherVersion}}")
testImplementation("org.mockito:mockito-core:5.0.0")
}
Loading