Use Gradle KTS in new Android app projects by default (#154061)

This PR resolves #151166
This commit is contained in:
Bartek Pacia 2024-10-18 22:46:01 +02:00 committed by GitHub
parent 0549bd8888
commit d3c54a115f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 133 additions and 112 deletions

View File

@ -29,14 +29,17 @@ Future<void> main() async {
await runProjectTest((FlutterProject flutterProject) async { await runProjectTest((FlutterProject flutterProject) async {
await inDirectory(path.join(flutterProject.rootPath, 'android'), () async { await inDirectory(path.join(flutterProject.rootPath, 'android'), () async {
section('Insert gradle testing script'); section('Insert gradle testing script');
final File build = File(path.join( final File buildFile = getAndroidBuildFile(path.join(flutterProject.rootPath, 'android'));
flutterProject.rootPath, 'android', 'app', 'build.gradle', buildFile.writeAsStringSync(
));
build.writeAsStringSync(
''' '''
task printEngineMavenUrl() { tasks.register("printEngineMavenUrl") {
doLast { doLast {
println project.repositories.find { it.name == 'maven' }.url project.repositories.forEach { repo ->
if (repo.name == "maven") {
repo as MavenArtifactRepository
logger.quiet(repo.url.toString())
}
}
} }
} }
''', ''',

View File

@ -256,18 +256,17 @@ class FlutterProject {
String get rootPath => path.join(parent.path, name); String get rootPath => path.join(parent.path, name);
String get androidPath => path.join(rootPath, 'android'); String get androidPath => path.join(rootPath, 'android');
String get iosPath => path.join(rootPath, 'ios'); String get iosPath => path.join(rootPath, 'ios');
File get appBuildFile => getAndroidBuildFile(androidPath);
Future<void> addCustomBuildType(String name, {required String initWith}) async { Future<void> addCustomBuildType(String name, {required String initWith}) async {
final File buildScript = File( final File buildScript = appBuildFile;
path.join(androidPath, 'app', 'build.gradle'),
);
buildScript.openWrite(mode: FileMode.append).write(''' buildScript.openWrite(mode: FileMode.append).write('''
android { android {
buildTypes { buildTypes {
$name { create("$name") {
initWith $initWith initWith(getByName("$initWith"))
} }
} }
} }
@ -288,14 +287,12 @@ android {
} }
Future<void> setMinSdkVersion(int sdkVersion) async { Future<void> setMinSdkVersion(int sdkVersion) async {
final File buildScript = File( final File buildScript = appBuildFile;
path.join(androidPath, 'app', 'build.gradle'),
);
buildScript.openWrite(mode: FileMode.append).write(''' buildScript.openWrite(mode: FileMode.append).write('''
android { android {
defaultConfig { defaultConfig {
minSdkVersion $sdkVersion minSdk = $sdkVersion
} }
} }
'''); ''');
@ -308,22 +305,20 @@ android {
} }
Future<void> addProductFlavors(Iterable<String> flavors) async { Future<void> addProductFlavors(Iterable<String> flavors) async {
final File buildScript = File( final File buildScript = appBuildFile;
path.join(androidPath, 'app', 'build.gradle'),
);
final String flavorConfig = flavors.map((String name) { final String flavorConfig = flavors.map((String name) {
return ''' return '''
$name { create("$name") {
applicationIdSuffix ".$name" applicationIdSuffix = ".$name"
versionNameSuffix "-$name" versionNameSuffix = "-$name"
} }
'''; ''';
}).join('\n'); }).join('\n');
buildScript.openWrite(mode: FileMode.append).write(''' buildScript.openWrite(mode: FileMode.append).write('''
android { android {
flavorDimensions "mode" flavorDimensions.add("mode")
productFlavors { productFlavors {
$flavorConfig $flavorConfig
} }
@ -332,9 +327,7 @@ android {
} }
Future<void> introduceError() async { Future<void> introduceError() async {
final File buildScript = File( final File buildScript = appBuildFile;
path.join(androidPath, 'app', 'build.gradle'),
);
await buildScript.writeAsString((await buildScript.readAsString()).replaceAll('buildTypes', 'builTypes')); await buildScript.writeAsString((await buildScript.readAsString()).replaceAll('buildTypes', 'builTypes'));
} }
@ -477,3 +470,14 @@ String? validateSnapshotDependency(FlutterProject project, String expectedTarget
return contentSnapshot.contains('$expectedTarget ') return contentSnapshot.contains('$expectedTarget ')
? null : 'Dependency file should have $expectedTarget as target. Instead found $contentSnapshot'; ? null : 'Dependency file should have $expectedTarget as target. Instead found $contentSnapshot';
} }
File getAndroidBuildFile(String androidPath) {
final File groovyFile = File(path.join(androidPath, 'app', 'build.gradle'));
final File kotlinFile = File(path.join(androidPath, 'app', 'build.gradle.kts'));
if (groovyFile.existsSync()) {
return groovyFile;
}
return kotlinFile;
}

View File

@ -467,7 +467,19 @@ class AndroidProject extends FlutterProjectPlatform {
static final RegExp _androidNamespacePattern = RegExp('android {[\\S\\s]+namespace\\s*=?\\s*[\'"](.+)[\'"]'); static final RegExp _androidNamespacePattern = RegExp('android {[\\S\\s]+namespace\\s*=?\\s*[\'"](.+)[\'"]');
static final RegExp _applicationIdPattern = RegExp('^\\s*applicationId\\s*=?\\s*[\'"](.*)[\'"]\\s*\$'); static final RegExp _applicationIdPattern = RegExp('^\\s*applicationId\\s*=?\\s*[\'"](.*)[\'"]\\s*\$');
static final RegExp _imperativeKotlinPluginPattern = RegExp('^\\s*apply plugin\\:\\s+[\'"]kotlin-android[\'"]\\s*\$'); static final RegExp _imperativeKotlinPluginPattern = RegExp('^\\s*apply plugin\\:\\s+[\'"]kotlin-android[\'"]\\s*\$');
static final RegExp _declarativeKotlinPluginPattern = RegExp('^\\s*id\\s+[\'"]kotlin-android[\'"]\\s*\$');
/// Examples of strings that this regex matches:
/// - `id "kotlin-android"`
/// - `id("kotlin-android")`
/// - `id ( "kotlin-android" ) `
/// - `id "org.jetbrains.kotlin.android"`
/// - `id("org.jetbrains.kotlin.android")`
/// - `id ( "org.jetbrains.kotlin.android" )`
static final List<RegExp> _declarativeKotlinPluginPatterns = <RegExp>[
RegExp('^\\s*id\\s*\\(?\\s*[\'"]kotlin-android[\'"]\\s*\\)?\\s*\$'),
RegExp('^\\s*id\\s*\\(?\\s*[\'"]org.jetbrains.kotlin.android[\'"]\\s*\\)?\\s*\$'),
];
/// Pattern used to find the assignment of the "group" property in Gradle. /// Pattern used to find the assignment of the "group" property in Gradle.
/// Expected example: `group "dev.flutter.plugin"` /// Expected example: `group "dev.flutter.plugin"`
@ -563,7 +575,9 @@ class AndroidProject extends FlutterProjectPlatform {
/// True, if the app project is using Kotlin. /// True, if the app project is using Kotlin.
bool get isKotlin { bool get isKotlin {
final bool imperativeMatch = firstMatchInFile(appGradleFile, _imperativeKotlinPluginPattern) != null; final bool imperativeMatch = firstMatchInFile(appGradleFile, _imperativeKotlinPluginPattern) != null;
final bool declarativeMatch = firstMatchInFile(appGradleFile, _declarativeKotlinPluginPattern) != null; final bool declarativeMatch = _declarativeKotlinPluginPatterns.any((RegExp pattern) {
return (firstMatchInFile(appGradleFile, pattern) != null);
});
return imperativeMatch || declarativeMatch; return imperativeMatch || declarativeMatch;
} }

View File

@ -1,8 +1,8 @@
plugins { plugins {
id "com.android.application" id("com.android.application")
id "kotlin-android" id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin" id("dev.flutter.flutter-gradle-plugin")
} }
android { android {
@ -16,7 +16,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8 jvmTarget = JavaVersion.VERSION_1_8.toString()
} }
defaultConfig { defaultConfig {
@ -34,7 +34,7 @@ android {
release { release {
// TODO: Add your own signing config for the release build. // TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug signingConfig = signingConfigs.getByName("debug")
} }
} }
} }

View File

@ -0,0 +1,18 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = file("../build")
subprojects {
project.buildDir = file("${rootProject.buildDir}/${project.name}")
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.buildDir)
}

View File

@ -1,18 +0,0 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

View File

@ -1,8 +1,8 @@
plugins { plugins {
id "com.android.application" id("com.android.application")
id "kotlin-android" id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin" id("dev.flutter.flutter-gradle-plugin")
} }
android { android {
@ -16,7 +16,7 @@ android {
} }
kotlinOptions { kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8 jvmTarget = JavaVersion.VERSION_1_8.toString()
} }
defaultConfig { defaultConfig {
@ -34,7 +34,7 @@ android {
release { release {
// TODO: Add your own signing config for the release build. // TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug signingConfig = signingConfigs.getByName("debug")
} }
} }
} }

View File

@ -0,0 +1,18 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = file("../build")
subprojects {
project.buildDir = file("${rootProject.buildDir}/${project.name}")
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.buildDir)
}

View File

@ -1,18 +0,0 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = "../build"
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1,25 @@
pluginManagement {
val flutterSdkPath = run {
val properties = java.util.Properties()
file("local.properties").inputStream().use { properties.load(it) }
val flutterSdkPath = properties.getProperty("flutter.sdk")
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
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 "{{agpVersion}}" apply false
id("org.jetbrains.kotlin.android") version "{{kotlinVersion}}" apply false
}
include(":app")

View File

@ -1,25 +0,0 @@
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 "{{agpVersion}}" apply false
id "org.jetbrains.kotlin.android" version "{{kotlinVersion}}" apply false
}
include ":app"

View File

@ -14,13 +14,13 @@
"templates/app_shared/.idea/workspace.xml.tmpl", "templates/app_shared/.idea/workspace.xml.tmpl",
"templates/app_shared/.metadata.tmpl", "templates/app_shared/.metadata.tmpl",
"templates/app_shared/analysis_options.yaml.tmpl", "templates/app_shared/analysis_options.yaml.tmpl",
"templates/app_shared/android-java.tmpl/app/build.gradle.tmpl", "templates/app_shared/android-java.tmpl/app/build.gradle.kts.tmpl",
"templates/app_shared/android-java.tmpl/app/src/main/java/androidIdentifier/MainActivity.java.tmpl", "templates/app_shared/android-java.tmpl/app/src/main/java/androidIdentifier/MainActivity.java.tmpl",
"templates/app_shared/android-java.tmpl/build.gradle.tmpl", "templates/app_shared/android-java.tmpl/build.gradle.kts.tmpl",
"templates/app_shared/android-java.tmpl/projectName_android.iml.tmpl", "templates/app_shared/android-java.tmpl/projectName_android.iml.tmpl",
"templates/app_shared/android-kotlin.tmpl/app/build.gradle.tmpl", "templates/app_shared/android-kotlin.tmpl/app/build.gradle.kts.tmpl",
"templates/app_shared/android-kotlin.tmpl/app/src/main/kotlin/androidIdentifier/MainActivity.kt.tmpl", "templates/app_shared/android-kotlin.tmpl/app/src/main/kotlin/androidIdentifier/MainActivity.kt.tmpl",
"templates/app_shared/android-kotlin.tmpl/build.gradle.tmpl", "templates/app_shared/android-kotlin.tmpl/build.gradle.kts.tmpl",
"templates/app_shared/android-kotlin.tmpl/projectName_android.iml.tmpl", "templates/app_shared/android-kotlin.tmpl/projectName_android.iml.tmpl",
"templates/app_shared/android.tmpl/.gitignore", "templates/app_shared/android.tmpl/.gitignore",
"templates/app_shared/android.tmpl/app/src/debug/AndroidManifest.xml.tmpl", "templates/app_shared/android.tmpl/app/src/debug/AndroidManifest.xml.tmpl",
@ -36,7 +36,7 @@
"templates/app_shared/android.tmpl/app/src/main/res/values/styles.xml", "templates/app_shared/android.tmpl/app/src/main/res/values/styles.xml",
"templates/app_shared/android.tmpl/app/src/profile/AndroidManifest.xml.tmpl", "templates/app_shared/android.tmpl/app/src/profile/AndroidManifest.xml.tmpl",
"templates/app_shared/android.tmpl/gradle.properties.tmpl", "templates/app_shared/android.tmpl/gradle.properties.tmpl",
"templates/app_shared/android.tmpl/settings.gradle.tmpl", "templates/app_shared/android.tmpl/settings.gradle.kts.tmpl",
"templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties.tmpl", "templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties.tmpl",
"templates/app_shared/android.tmpl/settings.gradle", "templates/app_shared/android.tmpl/settings.gradle",
"templates/app_shared/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl", "templates/app_shared/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl",

View File

@ -44,7 +44,7 @@ void main() {
test( test(
'build succeeds targeting string compileSdkVersion', 'build succeeds targeting string compileSdkVersion',
() async { () async {
final File buildGradleFile = exampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle'); final File buildGradleFile = exampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle.kts');
// write a build.gradle with compileSdkVersion as `android-UpsideDownCake` which is a string preview version // write a build.gradle with compileSdkVersion as `android-UpsideDownCake` which is a string preview version
buildGradleFile.writeAsStringSync( buildGradleFile.writeAsStringSync(
buildGradleFile.readAsStringSync().replaceFirst(compileSdkVersionMatch, 'compileSdkVersion = "android-UpsideDownCake"'), buildGradleFile.readAsStringSync().replaceFirst(compileSdkVersionMatch, 'compileSdkVersion = "android-UpsideDownCake"'),
@ -72,7 +72,7 @@ void main() {
test( test(
'build succeeds targeting string compileSdkPreview', 'build succeeds targeting string compileSdkPreview',
() async { () async {
final File buildGradleFile = exampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle'); final File buildGradleFile = exampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle.kts');
// write a build.gradle with compileSdkPreview as `UpsideDownCake` which is a string preview version // write a build.gradle with compileSdkPreview as `UpsideDownCake` which is a string preview version
buildGradleFile.writeAsStringSync( buildGradleFile.writeAsStringSync(
buildGradleFile.readAsStringSync().replaceFirst(compileSdkVersionMatch, 'compileSdkPreview = "UpsideDownCake"'), buildGradleFile.readAsStringSync().replaceFirst(compileSdkVersionMatch, 'compileSdkPreview = "UpsideDownCake"'),
@ -100,7 +100,7 @@ void main() {
test( test(
'build succeeds when both example app and plugin target compileSdkPreview', 'build succeeds when both example app and plugin target compileSdkPreview',
() async { () async {
final File appBuildGradleFile = exampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle'); final File appBuildGradleFile = exampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle.kts');
// write a build.gradle with compileSdkPreview as `UpsideDownCake` which is a string preview version // write a build.gradle with compileSdkPreview as `UpsideDownCake` which is a string preview version
appBuildGradleFile.writeAsStringSync( appBuildGradleFile.writeAsStringSync(
appBuildGradleFile.readAsStringSync().replaceFirst(compileSdkVersionMatch, 'compileSdkPreview = "UpsideDownCake"'), appBuildGradleFile.readAsStringSync().replaceFirst(compileSdkVersionMatch, 'compileSdkPreview = "UpsideDownCake"'),

View File

@ -3126,9 +3126,9 @@ void main() {
await runner.run(<String>['create', '--no-pub', projectDir.path]); await runner.run(<String>['create', '--no-pub', projectDir.path]);
expect(globals.fs.isFileSync('${projectDir.path}/android/app/build.gradle'), true); expect(globals.fs.isFileSync('${projectDir.path}/android/app/build.gradle.kts'), true);
final String buildContent = await globals.fs.file('${projectDir.path}/android/app/build.gradle').readAsString(); final String buildContent = await globals.fs.file('${projectDir.path}/android/app/build.gradle.kts').readAsString();
expect(buildContent.contains('compileSdk = flutter.compileSdkVersion'), true); expect(buildContent.contains('compileSdk = flutter.compileSdkVersion'), true);
expect(buildContent.contains('ndkVersion = flutter.ndkVersion'), true); expect(buildContent.contains('ndkVersion = flutter.ndkVersion'), true);

View File

@ -54,7 +54,7 @@ void main() {
final Directory pluginExampleAppDir = pluginAppDir.childDirectory('example'); final Directory pluginExampleAppDir = pluginAppDir.childDirectory('example');
final File projectGradleFile = pluginExampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle'); final File projectGradleFile = pluginExampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle.kts');
expect(projectGradleFile, exists); expect(projectGradleFile, exists);
final String projectBuildGradle = projectGradleFile.readAsStringSync(); final String projectBuildGradle = projectGradleFile.readAsStringSync();

View File

@ -51,7 +51,7 @@ void main() {
final Directory exampleAppDir = final Directory exampleAppDir =
tempDir.childDirectory(testName).childDirectory('example'); tempDir.childDirectory(testName).childDirectory('example');
final File buildGradleFile = exampleAppDir.childDirectory('android').childFile('build.gradle'); final File buildGradleFile = exampleAppDir.childDirectory('android').childFile('build.gradle.kts');
expect(buildGradleFile, exists); expect(buildGradleFile, exists);
final String buildGradle = buildGradleFile.readAsStringSync(); final String buildGradle = buildGradleFile.readAsStringSync();

View File

@ -53,7 +53,7 @@ void main() {
final Directory pluginExampleAppDir = pluginAppDir.childDirectory('example'); final Directory pluginExampleAppDir = pluginAppDir.childDirectory('example');
final File projectGradleFile = pluginExampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle'); final File projectGradleFile = pluginExampleAppDir.childDirectory('android').childDirectory('app').childFile('build.gradle.kts');
expect(projectGradleFile, exists); expect(projectGradleFile, exists);
final String projectBuildGradle = projectGradleFile.readAsStringSync(); final String projectBuildGradle = projectGradleFile.readAsStringSync();

View File

@ -160,7 +160,7 @@ Future<ProcessResult> buildFlutterApkWithSpecifiedDependencyVersions({
if (versions.compileSdkVersion != null) { if (versions.compileSdkVersion != null) {
final File appGradleBuild = File(fileSystem.path.join( final File appGradleBuild = File(fileSystem.path.join(
app.path, 'android', 'app', 'build.gradle')); app.path, 'android', 'app', 'build.gradle.kts'));
final String appBuildContent = appGradleBuild.readAsStringSync() final String appBuildContent = appGradleBuild.readAsStringSync()
.replaceFirst(flutterCompileSdkString, versions.compileSdkVersion!); .replaceFirst(flutterCompileSdkString, versions.compileSdkVersion!);
appGradleBuild.writeAsStringSync(appBuildContent); appGradleBuild.writeAsStringSync(appBuildContent);