Skip to content
Merged
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
2 changes: 1 addition & 1 deletion dev/integration_tests/ui/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

plugins {
id "com.android.application"
id "dev.flutter.flutter-gradle-plugin"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}

android {
Expand Down
5 changes: 3 additions & 2 deletions packages/flutter_tools/gradle/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ gradlePlugin {

dependencies {
// When bumping, also update:
// * ndkVersion in FlutterExtension in packages/flutter_tools/gradle/src/main/flutter.groovy
// * ndkVersion in FlutterExtension in packages/flutter_tools/gradle/src/main/groovy/flutter.groovy
// * AGP version in the buildscript block in packages/flutter_tools/gradle/src/main/groovy/flutter.groovy
// * AGP version in the buildscript block in packages/flutter_tools/gradle/src/main/kotlin/dependency_version_checker.gradle.kts
// * AGP version constants in packages/flutter_tools/lib/src/android/gradle_utils.dart
// * AGP version in buildscript block in packages/flutter_tools/gradle/src/main/flutter.groovy
compileOnly("com.android.tools.build:gradle:7.3.0")
}
26 changes: 25 additions & 1 deletion packages/flutter_tools/gradle/src/main/groovy/flutter.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ buildscript {
}
dependencies {
// When bumping, also update:
// * ndkVersion in FlutterExtension in packages/flutter_tools/gradle/src/main/flutter.groovy
// * ndkVersion in FlutterExtension in packages/flutter_tools/gradle/src/main/groovy/flutter.groovy
// * AGP version in the buildscript block in packages/flutter_tools/gradle/src/main/kotlin/dependency_version_checker.gradle.kts
// * AGP version constants in packages/flutter_tools/lib/src/android/gradle_utils.dart
// * AGP version in dependencies block in packages/flutter_tools/gradle/build.gradle.kts
classpath("com.android.tools.build:gradle:7.3.0")
Expand Down Expand Up @@ -321,6 +322,27 @@ class FlutterPlugin implements Plugin<Project> {
String flutterExecutableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "flutter.bat" : "flutter"
flutterExecutable = Paths.get(flutterRoot.absolutePath, "bin", flutterExecutableName).toFile()

// Validate that the provided Gradle, Java, AGP, and KGP versions are all within our
// supported range.
// TODO(gmackall) Dependency version checking is currently implemented as an additional
// Gradle plugin because we can't import it from Groovy code. As part of the Groovy
// -> Kotlin migration, we should remove this complexity and perform the checks inside
// of the main Flutter Gradle Plugin.
// See https://github.com/flutter/flutter/issues/121541#issuecomment-1920363687.
final Boolean shouldSkipDependencyChecks = project.hasProperty("skipDependencyChecks") && project.getProperty("skipDependencyChecks");
if (!shouldSkipDependencyChecks) {
try {
final String dependencyCheckerPluginPath = Paths.get(flutterRoot.absolutePath,
"packages", "flutter_tools", "gradle", "src", "main", "kotlin",
"dependency_version_checker.gradle.kts")
project.apply from: dependencyCheckerPluginPath
} catch (Exception ignored) {
project.logger.error("Warning: Flutter was unable to detect project Gradle, Java, " +
"AGP, and KGP versions. Skipping dependency version checking. Error was: "
+ ignored)
}
}

// Use Kotlin DSL to handle baseApplicationName logic due to Groovy dynamic dispatch bug.
project.apply from: Paths.get(flutterRoot.absolutePath, "packages", "flutter_tools", "gradle", "src", "main", "kotlin", "flutter.gradle.kts")

Expand Down Expand Up @@ -1515,6 +1537,8 @@ abstract class BaseFlutterTask extends DefaultTask {
@Optional @Input
Boolean validateDeferredComponents

@Optional @Input
Boolean skipDependencyChecks
@Optional @Input
String flavor

Expand Down

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions packages/flutter_tools/lib/src/android/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ version.
SDK versions are updated (you should see these fail if you do not fix them
preemptively).

Also, make sure to also update to the same version in the following places:
- The version in the buildscript block in `packages/flutter_tools/gradle/src/main/groovy/flutter.groovy`.
- The version in the buildscript block in `packages/flutter_tools/gradle/src/main/kotlin/dependency_version_checker.gradle.kts`.
- The version in the dependencies block in `packages/flutter_tools/gradle/build.gradle.kts`.

#### Gradle
When updating the Gradle version used in project templates
(`templateDefaultGradleVersion`), make sure that:
Expand Down
3 changes: 3 additions & 0 deletions packages/flutter_tools/lib/src/android/gradle.dart
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,9 @@ class AndroidGradleBuilder implements AndroidBuilder {
if (!buildInfo.androidGradleDaemon) {
command.add('--no-daemon');
}
if (buildInfo.androidSkipBuildDependencyValidation) {
command.add('-PskipDependencyChecks=true');
}
final LocalEngineInfo? localEngineInfo = _artifacts.localEngineInfo;
if (localEngineInfo != null) {
final Directory localEngineRepo = _getLocalEngineRepo(
Expand Down
5 changes: 5 additions & 0 deletions packages/flutter_tools/lib/src/build_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class BuildInfo {
this.nullSafetyMode = NullSafetyMode.sound,
this.codeSizeDirectory,
this.androidGradleDaemon = true,
this.androidSkipBuildDependencyValidation = false,
this.packageConfig = PackageConfig.empty,
this.initializeFromDill,
this.assumeInitializeFromDillUpToDate = false,
Expand Down Expand Up @@ -158,6 +159,10 @@ class BuildInfo {
/// The Gradle daemon may also be disabled in the Android application's properties file.
final bool androidGradleDaemon;

/// Whether to skip checking of individual versions of our Android build time
/// dependencies.
final bool androidSkipBuildDependencyValidation;

/// Additional key value pairs that are passed directly to the gradle project via the `-P`
/// flag.
final List<String> androidProjectArgs;
Expand Down
11 changes: 11 additions & 0 deletions packages/flutter_tools/lib/src/runner/flutter_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ abstract final class FlutterOptions {
static const String kAndroidGradleDaemon = 'android-gradle-daemon';
static const String kDeferredComponents = 'deferred-components';
static const String kAndroidProjectArgs = 'android-project-arg';
static const String kAndroidSkipBuildDependencyValidation = 'android-skip-build-dependency-validation';
static const String kInitializeFromDill = 'initialize-from-dill';
static const String kAssumeInitializeFromDillUpToDate = 'assume-initialize-from-dill-up-to-date';
static const String kNativeAssetsYamlFile = 'native-assets-yaml-file';
Expand Down Expand Up @@ -974,6 +975,12 @@ abstract class FlutterCommand extends Command<void> {
defaultsTo: true,
hide: hide,
);
argParser.addFlag(
FlutterOptions.kAndroidSkipBuildDependencyValidation,
help: 'Whether to skip version checking for Java, Gradle, '
'the Android Gradle Plugin (AGP), and the Kotlin Gradle Plugin (KGP)'
' during Android builds.',
);
argParser.addMultiOption(
FlutterOptions.kAndroidProjectArgs,
help: 'Additional arguments specified as key=value that are passed directly to the gradle '
Expand Down Expand Up @@ -1228,6 +1235,9 @@ abstract class FlutterCommand extends Command<void> {
final bool androidGradleDaemon = !argParser.options.containsKey(FlutterOptions.kAndroidGradleDaemon)
|| boolArg(FlutterOptions.kAndroidGradleDaemon);

final bool androidSkipBuildDependencyValidation = !argParser.options.containsKey(FlutterOptions.kAndroidSkipBuildDependencyValidation)
|| boolArg(FlutterOptions.kAndroidSkipBuildDependencyValidation);

final List<String> androidProjectArgs = argParser.options.containsKey(FlutterOptions.kAndroidProjectArgs)
? stringsArg(FlutterOptions.kAndroidProjectArgs)
: <String>[];
Expand Down Expand Up @@ -1323,6 +1333,7 @@ abstract class FlutterCommand extends Command<void> {
nullSafetyMode: nullSafetyMode,
codeSizeDirectory: codeSizeDirectory,
androidGradleDaemon: androidGradleDaemon,
androidSkipBuildDependencyValidation: androidSkipBuildDependencyValidation,
packageConfig: packageConfig,
androidProjectArgs: androidProjectArgs,
initializeFromDill: argParser.options.containsKey(FlutterOptions.kInitializeFromDill)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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"
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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"
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
// 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 'dart:io';

import 'package:file/src/interface/file_system_entity.dart';

import '../integration.shard/test_utils.dart';
import '../src/common.dart';
import '../src/context.dart';

const String gradleSettingsFileContent = r'''
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()

includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")

repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "AGP_REPLACE_ME" apply false
id "org.jetbrains.kotlin.android" version "KGP_REPLACE_ME" apply false
}

include ":app"

''';

const String agpReplacementString = 'AGP_REPLACE_ME';
const String kgpReplacementString = 'KGP_REPLACE_ME';

const String gradleWrapperPropertiesFileContent = r'''
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-GRADLE_REPLACE_ME-all.zip

''';

const String gradleReplacementString = 'GRADLE_REPLACE_ME';

// This test is currently on the preview shard (but not using the preview
// version of Android) because it is the only one using Java 11. This test
// requires Java 11 due to the intentionally low version of Gradle.
void main() {
late Directory tempDir;

setUpAll(() async {
tempDir = createResolvedTempDirectorySync('run_test.');
});

tearDownAll(() async {
tryToDelete(tempDir as FileSystemEntity);
});

testUsingContext(
'AGP version out of "warn" support band prints warning but still builds', () async {
// Create a new flutter project.
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
ProcessResult result = await processManager.run(<String>[
flutterBin,
'create',
'dependency_checker_app',
'--platforms=android',
], workingDirectory: tempDir.path);
expect(result, const ProcessResultMatcher());
const String gradleVersion = '7.5';
const String agpVersion = '4.2.0';
const String kgpVersion = '1.7.10';

final Directory app = Directory(fileSystem.path.join(tempDir.path, 'dependency_checker_app'));

// Modify gradle version to passed in version.
final File gradleWrapperProperties = File(fileSystem.path.join(
app.path, 'android', 'gradle', 'wrapper', 'gradle-wrapper.properties'));
final String propertyContent = gradleWrapperPropertiesFileContent.replaceFirst(
gradleReplacementString,
gradleVersion,
);
await gradleWrapperProperties.writeAsString(propertyContent, flush: true);

final File gradleSettings = File(fileSystem.path.join(
app.path, 'android', 'settings.gradle'));
final String settingsContent = gradleSettingsFileContent
.replaceFirst(agpReplacementString, agpVersion)
.replaceFirst(kgpReplacementString, kgpVersion);
await gradleSettings.writeAsString(settingsContent, flush: true);


// Ensure that gradle files exists from templates.
result = await processManager.run(<String>[
flutterBin,
'build',
'apk',
'--debug',
], workingDirectory: app.path);
expect(result, const ProcessResultMatcher());
expect(result.stderr, contains('Please upgrade your Android Gradle '
'Plugin version'));
});

testUsingContext(
'Gradle version out of "warn" support band prints warning but still builds', () async {
// Create a new flutter project.
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
ProcessResult result = await processManager.run(<String>[
flutterBin,
'create',
'dependency_checker_app',
'--platforms=android',
], workingDirectory: tempDir.path);
expect(result, const ProcessResultMatcher());
const String gradleVersion = '7.0';
const String agpVersion = '4.2.0';
const String kgpVersion = '1.7.10';

final Directory app = Directory(fileSystem.path.join(tempDir.path, 'dependency_checker_app'));

// Modify gradle version to passed in version.
final File gradleWrapperProperties = File(fileSystem.path.join(
app.path, 'android', 'gradle', 'wrapper', 'gradle-wrapper.properties'));
final String propertyContent = gradleWrapperPropertiesFileContent.replaceFirst(
gradleReplacementString,
gradleVersion,
);
await gradleWrapperProperties.writeAsString(propertyContent, flush: true);

final File gradleSettings = File(fileSystem.path.join(
app.path, 'android', 'settings.gradle'));
final String settingsContent = gradleSettingsFileContent
.replaceFirst(agpReplacementString, agpVersion)
.replaceFirst(kgpReplacementString, kgpVersion);
await gradleSettings.writeAsString(settingsContent, flush: true);


// Ensure that gradle files exists from templates.
result = await processManager.run(<String>[
flutterBin,
'build',
'apk',
'--debug',
], workingDirectory: app.path);
expect(result, const ProcessResultMatcher());
expect(result.stderr, contains('Please upgrade your Gradle version'));
});

testUsingContext(
'Kotlin version out of "warn" support band prints warning but still builds', () async {
// Create a new flutter project.
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
ProcessResult result = await processManager.run(<String>[
flutterBin,
'create',
'dependency_checker_app',
'--platforms=android',
], workingDirectory: tempDir.path);
expect(result, const ProcessResultMatcher());
const String gradleVersion = '7.5';
const String agpVersion = '7.4.0';
const String kgpVersion = '1.4.10';

final Directory app = Directory(fileSystem.path.join(tempDir.path, 'dependency_checker_app'));

// Modify gradle version to passed in version.
final File gradleWrapperProperties = File(fileSystem.path.join(
app.path, 'android', 'gradle', 'wrapper', 'gradle-wrapper.properties'));
final String propertyContent = gradleWrapperPropertiesFileContent.replaceFirst(
gradleReplacementString,
gradleVersion,
);
await gradleWrapperProperties.writeAsString(propertyContent, flush: true);

final File gradleSettings = File(fileSystem.path.join(
app.path, 'android', 'settings.gradle'));
final String settingsContent = gradleSettingsFileContent
.replaceFirst(agpReplacementString, agpVersion)
.replaceFirst(kgpReplacementString, kgpVersion);
await gradleSettings.writeAsString(settingsContent, flush: true);


// Ensure that gradle files exists from templates.
result = await processManager.run(<String>[
flutterBin,
'build',
'apk',
'--debug',
], workingDirectory: app.path);
expect(result, const ProcessResultMatcher());
expect(result.stderr, contains('Please upgrade your Kotlin version'));
});

// TODO(gmackall): Add tests for build blocking when the
// corresponding error versions are enabled.
}