diff --git a/examples/api/android/app/build.gradle b/examples/api/android/app/build.gradle index a29a2a8cf314..8a96516eda97 100644 --- a/examples/api/android/app/build.gradle +++ b/examples/api/android/app/build.gradle @@ -29,6 +29,16 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + android { compileSdkVersion flutter.compileSdkVersion @@ -48,8 +58,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "dev.flutter.flutter_api_samples" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/examples/flutter_view/android/app/build.gradle b/examples/flutter_view/android/app/build.gradle index 0fe260689bb2..bab449d7a3e0 100644 --- a/examples/flutter_view/android/app/build.gradle +++ b/examples/flutter_view/android/app/build.gradle @@ -28,6 +28,16 @@ if (flutterVersionName == null) { apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + android { compileSdkVersion flutter.compileSdkVersion @@ -38,8 +48,8 @@ android { defaultConfig { applicationId "io.flutter.examples.flutter_view" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/examples/hello_world/android/app/build.gradle b/examples/hello_world/android/app/build.gradle index 17652d11b18a..7a01c1567c3c 100644 --- a/examples/hello_world/android/app/build.gradle +++ b/examples/hello_world/android/app/build.gradle @@ -28,6 +28,16 @@ if (flutterVersionName == null) { apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + android { compileSdkVersion flutter.compileSdkVersion @@ -38,8 +48,8 @@ android { defaultConfig { applicationId "io.flutter.examples.hello_world" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/examples/image_list/android/app/build.gradle b/examples/image_list/android/app/build.gradle index 4615c0c0e59f..20281c7d1ebf 100644 --- a/examples/image_list/android/app/build.gradle +++ b/examples/image_list/android/app/build.gradle @@ -28,6 +28,16 @@ if (flutterVersionName == null) { apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + android { compileSdkVersion flutter.compileSdkVersion @@ -39,8 +49,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.image_list" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/examples/layers/android/app/build.gradle b/examples/layers/android/app/build.gradle index ae5db5ac1dbc..2b92cb6c4ff5 100644 --- a/examples/layers/android/app/build.gradle +++ b/examples/layers/android/app/build.gradle @@ -28,6 +28,16 @@ if (flutterVersionName == null) { apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + android { compileSdkVersion flutter.compileSdkVersion @@ -38,8 +48,8 @@ android { defaultConfig { applicationId "io.flutter.examples.layers" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/examples/platform_channel/android/app/build.gradle b/examples/platform_channel/android/app/build.gradle index 130943759c7a..cce72b04647c 100644 --- a/examples/platform_channel/android/app/build.gradle +++ b/examples/platform_channel/android/app/build.gradle @@ -28,6 +28,16 @@ if (flutterVersionName == null) { apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + android { compileSdkVersion flutter.compileSdkVersion @@ -38,8 +48,8 @@ android { defaultConfig { applicationId "io.flutter.examples.platform_channel" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/examples/platform_view/android/app/build.gradle b/examples/platform_view/android/app/build.gradle index 0e12c7e4f84e..19a96a7bfbc9 100644 --- a/examples/platform_view/android/app/build.gradle +++ b/examples/platform_view/android/app/build.gradle @@ -28,6 +28,16 @@ if (flutterVersionName == null) { apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + android { compileSdkVersion flutter.compileSdkVersion @@ -38,8 +48,8 @@ android { defaultConfig { applicationId "io.flutter.examples.platform_view" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/packages/flutter_tools/README.md b/packages/flutter_tools/README.md index e46de50f17b4..c52201c29cb7 100644 --- a/packages/flutter_tools/README.md +++ b/packages/flutter_tools/README.md @@ -97,7 +97,7 @@ variable to be set. The full invocation to run everything might therefore look something like: ```shell -$ FLUTTER_ROOT=~/path/to/flutter-sdk +$ export FLUTTER_ROOT=~/path/to/flutter-sdk $ flutter test --concurrency 1 ``` diff --git a/packages/flutter_tools/gradle/flutter.gradle b/packages/flutter_tools/gradle/flutter.gradle index 744e89c9cffd..68be573435f4 100644 --- a/packages/flutter_tools/gradle/flutter.gradle +++ b/packages/flutter_tools/gradle/flutter.gradle @@ -139,6 +139,11 @@ class FlutterPlugin implements Plugin { private Properties localProperties private String engineVersion + /** + * Flutter Docs Website references URLs for help messages. + */ + private final String kWebsiteDeploymentAndroidBuildConfig = 'https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration' + @Override void apply(Project project) { this.project = project @@ -300,7 +305,7 @@ class FlutterPlugin implements Plugin { localEngine = engineOut.name localEngineSrcPath = engineOut.parentFile.parent } - project.android.buildTypes.all this.&addFlutterDependencies + project.android.buildTypes.all this.&addFlutterDependencies } private static Boolean shouldShrinkResources(Project project) { @@ -409,9 +414,33 @@ class FlutterPlugin implements Plugin { // Wait until the Android plugin loaded. pluginProject.afterEvaluate { + Boolean showBuildConfigurationMessage = false + + // Checks if there is a mismatch between the plugin compileSdkVersion and the project compileSdkVersion. if (pluginProject.android.compileSdkVersion > project.android.compileSdkVersion) { project.logger.quiet("Warning: The plugin ${pluginName} requires Android SDK version ${pluginProject.android.compileSdkVersion.substring(8)}.") + showBuildConfigurationMessage = true + } + + // Checks if there is a mismatch between the plugin minSdkVersion and the project minSdkVersion. + if(pluginProject.android.defaultConfig?.minSdkVersion?.apiLevel > project.android.defaultConfig?.minSdkVersion?.apiLevel) { + project.logger.quiet("Warning: The plugin ${pluginName} requires minSdkVersion ${pluginProject.android.defaultConfig?.minSdkVersion?.apiLevel}.") + showBuildConfigurationMessage = true + + if (!resolveProperty("flutter.minSdkVersion", null)) { + project.logger.quiet("flutter.minSdkVersion not found on ${project.projectDir.parentFile}${File.separator}local.properties, consider adding it. Using ${project.android.defaultConfig.minSdkVersion.apiLevel} as default.") + } + + // Additionally checks if the targetSdkVersion was set. + if (!resolveProperty("flutter.targetSdkVersion", null)) { + project.logger.quiet("flutter.targetSdkVersion not found on ${project.projectDir.parentFile}${File.separator}local.properties, consider adding it. Using ${project.android.defaultConfig.targetSdkVersion.apiLevel} as default.") + } } + + if (showBuildConfigurationMessage) { + project.logger.quiet("For more information about build configuration, see $kWebsiteDeploymentAndroidBuildConfig.") + } + project.android.buildTypes.all addEmbeddingDependencyToPlugin } } diff --git a/packages/flutter_tools/lib/src/android/gradle_errors.dart b/packages/flutter_tools/lib/src/android/gradle_errors.dart index f8d5436ca3bd..6d1c3873fcbc 100644 --- a/packages/flutter_tools/lib/src/android/gradle_errors.dart +++ b/packages/flutter_tools/lib/src/android/gradle_errors.dart @@ -390,27 +390,24 @@ final GradleHandledError minSdkVersion = GradleHandledError( required bool usesAndroidX, required bool multidexEnabled, }) async { - final File gradleFile = project.directory + final File localPropertiesFile = project.directory .childDirectory('android') - .childDirectory('app') - .childFile('build.gradle'); + .childFile('local.properties'); final Match? minSdkVersionMatch = _minSdkVersionPattern.firstMatch(line); assert(minSdkVersionMatch?.groupCount == 3); final String textInBold = globals.logger.terminal.bolden( - 'Fix this issue by adding the following to the file ${gradleFile.path}:\n' - 'android {\n' - ' defaultConfig {\n' - ' minSdkVersion ${minSdkVersionMatch?.group(2)}\n' - ' }\n' - '}\n' + 'Fix this issue by adding the following to the file ${localPropertiesFile.path}:\n' + '\n' + 'flutter.minSdkVersion=${minSdkVersionMatch?.group(2)}\n' ); globals.printBox( 'The plugin ${minSdkVersionMatch?.group(3)} requires a higher Android SDK version.\n' '$textInBold\n' "Note that your app won't be available to users running Android SDKs below ${minSdkVersionMatch?.group(2)}.\n" - 'Alternatively, try to find a version of this plugin that supports these lower versions of the Android SDK.', + 'Alternatively, try to find a version of this plugin that supports these lower versions of the Android SDK.\n' + 'For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration', title: _boxTitle, ); return GradleBuildStatus.exit; @@ -518,8 +515,8 @@ final GradleHandledError minCompileSdkVersionHandler = GradleHandledError( required bool usesAndroidX, required bool multidexEnabled, }) async { - final Match? minSdkVersionMatch = _minCompileSdkVersionPattern.firstMatch(line); - assert(minSdkVersionMatch?.groupCount == 1); + final Match? minCompileSdkVersionMatch = _minCompileSdkVersionPattern.firstMatch(line); + assert(minCompileSdkVersionMatch?.groupCount == 1); final File gradleFile = project.directory .childDirectory('android') @@ -529,7 +526,7 @@ final GradleHandledError minCompileSdkVersionHandler = GradleHandledError( '${globals.logger.terminal.warningMark} Your project requires a higher compileSdkVersion.\n' 'Fix this issue by bumping the compileSdkVersion in ${gradleFile.path}:\n' 'android {\n' - ' compileSdkVersion ${minSdkVersionMatch?.group(1)}\n' + ' compileSdkVersion ${minCompileSdkVersionMatch?.group(1)}\n' '}', title: _boxTitle, ); diff --git a/packages/flutter_tools/templates/app_shared/android-java.tmpl/app/build.gradle.tmpl b/packages/flutter_tools/templates/app_shared/android-java.tmpl/app/build.gradle.tmpl index 2ebd98494445..7dc3413ef520 100644 --- a/packages/flutter_tools/templates/app_shared/android-java.tmpl/app/build.gradle.tmpl +++ b/packages/flutter_tools/templates/app_shared/android-java.tmpl/app/build.gradle.tmpl @@ -25,6 +25,16 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + android { compileSdkVersion flutter.compileSdkVersion ndkVersion flutter.ndkVersion @@ -37,8 +47,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "{{androidIdentifier}}" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/app/build.gradle.tmpl b/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/app/build.gradle.tmpl index c69744f37259..336682df8858 100644 --- a/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/app/build.gradle.tmpl +++ b/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/app/build.gradle.tmpl @@ -25,6 +25,16 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + android { compileSdkVersion flutter.compileSdkVersion ndkVersion flutter.ndkVersion @@ -45,8 +55,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "{{androidIdentifier}}" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/packages/flutter_tools/templates/module/android/library_new_embedding/Flutter.tmpl/build.gradle.tmpl b/packages/flutter_tools/templates/module/android/library_new_embedding/Flutter.tmpl/build.gradle.tmpl index 0ca0966be8fe..09593e9b12a9 100644 --- a/packages/flutter_tools/templates/module/android/library_new_embedding/Flutter.tmpl/build.gradle.tmpl +++ b/packages/flutter_tools/templates/module/android/library_new_embedding/Flutter.tmpl/build.gradle.tmpl @@ -26,6 +26,16 @@ if (flutterVersionName == null) { apply plugin: 'com.android.library' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + group '{{androidIdentifier}}' version '1.0' @@ -39,8 +49,8 @@ android { } defaultConfig { - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 069d6b20006f..7b12233588af 100755 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -2479,7 +2479,7 @@ void main() { expect(env['flutter'].allows(Version(2, 4, 9)), false); }); - testUsingContext('default app uses flutter default versions', () async { + testUsingContext('default app uses local properties or flutter default versions', () async { Cache.flutterRoot = '../..'; final CreateCommand command = CreateCommand(); @@ -2493,7 +2493,8 @@ void main() { expect(buildContent.contains('compileSdkVersion flutter.compileSdkVersion'), true); expect(buildContent.contains('ndkVersion flutter.ndkVersion'), true); - expect(buildContent.contains('targetSdkVersion flutter.targetSdkVersion'), true); + expect(buildContent.contains('minSdkVersion flutterMinSdkVersion'), true); + expect(buildContent.contains('targetSdkVersion flutterTargetSdkVersion'), true); }); testUsingContext('Linux plugins handle partially camel-case project names correctly', () async { diff --git a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart index f30f3e0a0e53..91ef0911e511 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart @@ -770,16 +770,15 @@ assembleProfile '\n' '┌─ Flutter Fix ─────────────────────────────────────────────────────────────────────────────────┐\n' '│ The plugin webview_flutter requires a higher Android SDK version. │\n' - '│ Fix this issue by adding the following to the file /android/app/build.gradle: │\n' - '│ android { │\n' - '│ defaultConfig { │\n' - '│ minSdkVersion 19 │\n' - '│ } │\n' - '│ } │\n' + '│ Fix this issue by adding the following to the file /android/local.properties: │\n' + '│ │\n' + '│ flutter.minSdkVersion=19 │\n' '│ │\n' "│ Note that your app won't be available to users running Android SDKs below 19. │\n" '│ Alternatively, try to find a version of this plugin that supports these lower versions of the │\n' '│ Android SDK. │\n' + '│ For more information, see: │\n' + '│ https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration │\n' '└───────────────────────────────────────────────────────────────────────────────────────────────┘\n' ) ); diff --git a/packages/integration_test/example/android/app/build.gradle b/packages/integration_test/example/android/app/build.gradle index bc4a84f721a4..be1d049aa8e2 100644 --- a/packages/integration_test/example/android/app/build.gradle +++ b/packages/integration_test/example/android/app/build.gradle @@ -28,6 +28,16 @@ if (flutterVersionName == null) { apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def flutterMinSdkVersion = localProperties.getProperty('flutter.minSdkVersion') +if (flutterMinSdkVersion == null) { + flutterMinSdkVersion = flutter.minSdkVersion +} + +def flutterTargetSdkVersion = localProperties.getProperty('flutter.targetSdkVersion') +if (flutterTargetSdkVersion == null) { + flutterTargetSdkVersion = flutter.targetSdkVersion +} + android { compileSdkVersion flutter.compileSdkVersion @@ -39,8 +49,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.integration_test_example" - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion + minSdkVersion flutterMinSdkVersion + targetSdkVersion flutterTargetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"