Unverified Commit 0a1af8a1 authored by Bartek Pacia's avatar Bartek Pacia Committed by GitHub

Add support for Gradle Kotlin DSL (#140744)

This PR resolves #140548. It's based on my work in #118067.
parent 5887d6c7
// 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.
// This file is auto generated.
// To update all the settings.gradle files in the Flutter repo,
// See dev/tools/bin/generate_gradle_lockfiles.dart.
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
}
settings.ext.flutterSdkPath = flutterSdkPath()
// Flutter Gradle Plugin ships together with the Flutter SDK
includeBuild("${settings.ext.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 "7.4.2" apply false
}
include ':app'
// 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.
// Contents of this file automatically generated by dev/tools/bin/generate_gradle_lockfiles.dart.
// Do not merge changes to this file. See #140115.
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 "7.4.2" apply false
}
include(":app")
...@@ -29,7 +29,8 @@ import org.gradle.api.tasks.bundling.Jar ...@@ -29,7 +29,8 @@ import org.gradle.api.tasks.bundling.Jar
import org.gradle.internal.os.OperatingSystem import org.gradle.internal.os.OperatingSystem
/** /**
* For apps only. Provides the flutter extension used in app/build.gradle. * For apps only. Provides the flutter extension used in the app-level Gradle
* build file (app/build.gradle or app/build.gradle.kts).
* *
* The versions specified here should match the values in * The versions specified here should match the values in
* packages/flutter_tools/lib/src/android/gradle_utils.dart, so when bumping, * packages/flutter_tools/lib/src/android/gradle_utils.dart, so when bumping,
...@@ -62,7 +63,7 @@ class FlutterExtension { ...@@ -62,7 +63,7 @@ class FlutterExtension {
/** /**
* Specifies the relative directory to the Flutter project directory. * Specifies the relative directory to the Flutter project directory.
* In an app project, this is ../.. since the app's build.gradle is under android/app. * In an app project, this is ../.. since the app's Gradle build file is under android/app.
*/ */
String source = "../.." String source = "../.."
...@@ -90,7 +91,8 @@ buildscript { ...@@ -90,7 +91,8 @@ buildscript {
/** /**
* Some apps don't set default compile options. * Some apps don't set default compile options.
* Apps can change these values in android/app/build.gradle. * Apps can change these values in the app-level Gradle build file
* (android/app/build.gradle or android/app/build.gradle.kts).
* This just ensures that default values are set. * This just ensures that default values are set.
*/ */
android { android {
...@@ -423,13 +425,12 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -423,13 +425,12 @@ class FlutterPlugin implements Plugin<Project> {
* just using the `plugins.android` list. * just using the `plugins.android` list.
*/ */
private configureLegacyPluginEachProjects(Project project) { private configureLegacyPluginEachProjects(Project project) {
File settingsGradle = new File(project.projectDir.parentFile, "settings.gradle")
try { try {
if (!settingsGradle.text.contains("'.flutter-plugins'")) { if (!settingsGradleFile(project).text.contains("'.flutter-plugins'")) {
return return
} }
} catch (FileNotFoundException ignored) { } catch (FileNotFoundException ignored) {
throw new GradleException("settings.gradle does not exist: ${settingsGradle.absolutePath}") throw new GradleException("settings.gradle/settings.gradle.kts does not exist: ${settingsGradleFile(project).absolutePath}")
} }
List<Map<String, Object>> deps = getPluginDependencies(project) List<Map<String, Object>> deps = getPluginDependencies(project)
List<String> plugins = getPluginList(project).collect { it.name as String } List<String> plugins = getPluginList(project).collect { it.name as String }
...@@ -438,7 +439,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -438,7 +439,7 @@ class FlutterPlugin implements Plugin<Project> {
Project pluginProject = project.rootProject.findProject(":${it.name}") Project pluginProject = project.rootProject.findProject(":${it.name}")
if (pluginProject == null) { if (pluginProject == null) {
// Plugin was not included in `settings.gradle`, but is listed in `.flutter-plugins`. // Plugin was not included in `settings.gradle`, but is listed in `.flutter-plugins`.
project.logger.error("Plugin project :${it.name} listed, but not found. Please fix your settings.gradle.") project.logger.error("Plugin project :${it.name} listed, but not found. Please fix your settings.gradle/settings.gradle.kts.")
} else if (doesSupportAndroidPlatform(pluginProject.projectDir.parentFile.path as String)) { } else if (doesSupportAndroidPlatform(pluginProject.projectDir.parentFile.path as String)) {
// Plugin has a functioning `android` folder and is included successfully, although it's not supported. // Plugin has a functioning `android` folder and is included successfully, although it's not supported.
// It must be configured nonetheless, to not throw an "Unresolved reference" exception. // It must be configured nonetheless, to not throw an "Unresolved reference" exception.
...@@ -451,11 +452,38 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -451,11 +452,38 @@ class FlutterPlugin implements Plugin<Project> {
// TODO(54566): Can remove this function and its call sites once resolved. // TODO(54566): Can remove this function and its call sites once resolved.
/** /**
* Returns `true` if the given path contains an `android/build.gradle` file. * Returns `true` if the given path contains an `android` directory
* containing a `build.gradle` or `build.gradle.kts` file.
*/
private Boolean doesSupportAndroidPlatform(String path) {
File buildGradle = new File(path, 'android' + File.separator + 'build.gradle')
File buildGradleKts = new File(path, 'android' + File.separator + 'build.gradle.kts')
if (buildGradle.exists() && buildGradleKts.exists()) {
logger.error(
"Both build.gradle and build.gradle.kts exist, so " +
"build.gradle.kts is ignored. This is likely a mistake."
)
}
return buildGradle.exists() || buildGradleKts.exists()
}
/**
* Returns the Gradle settings script for the build. When both Groovy and
* Kotlin variants exist, then Groovy (settings.gradle) is preferred over
* Kotlin (settings.gradle.kts). This is the same behavior as Gradle 8.5.
*/ */
private static Boolean doesSupportAndroidPlatform(String path) { private File settingsGradleFile(Project project) {
File editableAndroidProject = new File(path, "android" + File.separator + "build.gradle") File settingsGradle = new File(project.projectDir.parentFile, "settings.gradle")
return editableAndroidProject.exists() File settingsGradleKts = new File(project.projectDir.parentFile, "settings.gradle.kts")
if (settingsGradle.exists() && settingsGradleKts.exists()) {
logger.error(
"Both settings.gradle and settings.gradle.kts exist, so " +
"settings.gradle.kts is ignored. This is likely a mistake."
)
}
return settingsGradle.exists() ? settingsGradle : settingsGradleKts
} }
/** Adds the plugin project dependency to the app project. */ /** Adds the plugin project dependency to the app project. */
......
...@@ -225,9 +225,15 @@ class _DeferredComponentAndroidFiles { ...@@ -225,9 +225,15 @@ class _DeferredComponentAndroidFiles {
Directory get componentDir => androidDir.childDirectory(name); Directory get componentDir => androidDir.childDirectory(name);
File get androidManifestFile => componentDir.childDirectory('src').childDirectory('main').childFile('AndroidManifest.xml'); File get androidManifestFile => componentDir.childDirectory('src').childDirectory('main').childFile('AndroidManifest.xml');
File get buildGradleFile => componentDir.childFile('build.gradle'); File get buildGradleFile {
if (componentDir.childFile('build.gradle').existsSync()) {
return componentDir.childFile('build.gradle');
}
return componentDir.childFile('build.gradle.kts');
}
// True when AndroidManifest.xml and build.gradle exist for the android dynamic feature. // True when AndroidManifest.xml and build.gradle/build.gradle.kts exist for
// the android dynamic feature.
bool verifyFilesExist() { bool verifyFilesExist() {
return androidManifestFile.existsSync() && buildGradleFile.existsSync(); return androidManifestFile.existsSync() && buildGradleFile.existsSync();
} }
......
...@@ -204,20 +204,26 @@ distributionUrl=https\\://services.gradle.org/distributions/gradle-$gradleVersio ...@@ -204,20 +204,26 @@ distributionUrl=https\\://services.gradle.org/distributions/gradle-$gradleVersio
/// The Android plugin version is specified in the [build.gradle] file within /// The Android plugin version is specified in the [build.gradle] file within
/// the project's Android directory. /// the project's Android directory.
String getGradleVersionForAndroidPlugin(Directory directory, Logger logger) { String getGradleVersionForAndroidPlugin(Directory directory, Logger logger) {
final File buildFile = directory.childFile('build.gradle'); const String buildFileName = 'build.gradle/build.gradle.kts';
File buildFile = directory.childFile('build.gradle');
if (!buildFile.existsSync()) {
buildFile = directory.childFile('build.gradle.kts');
}
if (!buildFile.existsSync()) { if (!buildFile.existsSync()) {
logger.printTrace( logger.printTrace(
"$buildFile doesn't exist, assuming Gradle version: $templateDefaultGradleVersion"); "$buildFileName doesn't exist, assuming Gradle version: $templateDefaultGradleVersion");
return templateDefaultGradleVersion; return templateDefaultGradleVersion;
} }
final String buildFileContent = buildFile.readAsStringSync(); final String buildFileContent = buildFile.readAsStringSync();
final Iterable<Match> pluginMatches = _buildAndroidGradlePluginRegExp.allMatches(buildFileContent); final Iterable<Match> pluginMatches = _buildAndroidGradlePluginRegExp.allMatches(buildFileContent);
if (pluginMatches.isEmpty) { if (pluginMatches.isEmpty) {
logger.printTrace("$buildFile doesn't provide an AGP version, assuming Gradle version: $templateDefaultGradleVersion"); logger.printTrace("$buildFileName doesn't provide an AGP version, assuming Gradle version: $templateDefaultGradleVersion");
return templateDefaultGradleVersion; return templateDefaultGradleVersion;
} }
final String? androidPluginVersion = pluginMatches.first.group(1); final String? androidPluginVersion = pluginMatches.first.group(1);
logger.printTrace('$buildFile provides AGP version: $androidPluginVersion'); logger.printTrace('$buildFileName provides AGP version: $androidPluginVersion');
return getGradleVersionFor(androidPluginVersion ?? 'unknown'); return getGradleVersionFor(androidPluginVersion ?? 'unknown');
} }
...@@ -325,9 +331,13 @@ OS: Mac OS X 13.2.1 aarch64 ...@@ -325,9 +331,13 @@ OS: Mac OS X 13.2.1 aarch64
/// [settings.gradle] file within the project's /// [settings.gradle] file within the project's
/// Android directory ([androidDirectory]). /// Android directory ([androidDirectory]).
String? getAgpVersion(Directory androidDirectory, Logger logger) { String? getAgpVersion(Directory androidDirectory, Logger logger) {
final File buildFile = androidDirectory.childFile('build.gradle'); File buildFile = androidDirectory.childFile('build.gradle');
if (!buildFile.existsSync()) {
buildFile = androidDirectory.childFile('build.gradle.kts');
}
if (!buildFile.existsSync()) { if (!buildFile.existsSync()) {
logger.printTrace('Can not find build.gradle in $androidDirectory'); logger.printTrace('Can not find build.gradle/build.gradle.kts in $androidDirectory');
return null; return null;
} }
final String buildFileContent = buildFile.readAsStringSync(); final String buildFileContent = buildFile.readAsStringSync();
......
...@@ -459,6 +459,10 @@ class AndroidProject extends FlutterProjectPlatform { ...@@ -459,6 +459,10 @@ class AndroidProject extends FlutterProjectPlatform {
static final RegExp _applicationIdPattern = RegExp('^\\s*applicationId\\s+[\'"](.*)[\'"]\\s*\$'); static final RegExp _applicationIdPattern = RegExp('^\\s*applicationId\\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*\$'); static final RegExp _declarativeKotlinPluginPattern = RegExp('^\\s*id\\s+[\'"]kotlin-android[\'"]\\s*\$');
/// Pattern used to find the assignment of the "group" property in Gradle.
/// Expected example: `group "dev.flutter.plugin"`
/// Regex is used in both Groovy and Kotlin Gradle files.
static final RegExp _groupPattern = RegExp('^\\s*group\\s+[\'"](.*)[\'"]\\s*\$'); static final RegExp _groupPattern = RegExp('^\\s*group\\s+[\'"](.*)[\'"]\\s*\$');
/// The Gradle root directory of the Android host app. This is the directory /// The Gradle root directory of the Android host app. This is the directory
...@@ -552,10 +556,54 @@ class AndroidProject extends FlutterProjectPlatform { ...@@ -552,10 +556,54 @@ class AndroidProject extends FlutterProjectPlatform {
return imperativeMatch || declarativeMatch; return imperativeMatch || declarativeMatch;
} }
/// Gets top-level Gradle build file.
/// See https://developer.android.com/build#top-level.
///
/// The file must exist and it must be written in either Groovy (build.gradle)
/// or Kotlin (build.gradle.kts).
File get hostAppGradleFile {
final File buildGroovy = hostAppGradleRoot.childFile('build.gradle');
final File buildKotlin = hostAppGradleRoot.childFile('build.gradle.kts');
if (buildGroovy.existsSync() && buildKotlin.existsSync()) {
// We mimic Gradle's behavior of preferring Groovy over Kotlin when both files exist.
return buildGroovy;
}
if (buildKotlin.existsSync()) {
return buildKotlin;
}
// TODO(bartekpacia): An exception should be thrown when neither
// build.gradle nor build.gradle.kts exist, instead of falling back to the
// Groovy file. See #141180.
return buildGroovy;
}
/// Gets the module-level build.gradle file. /// Gets the module-level build.gradle file.
/// See https://developer.android.com/build#module-level. /// See https://developer.android.com/build#module-level.
File get appGradleFile => hostAppGradleRoot.childDirectory('app') ///
.childFile('build.gradle'); /// The file must exist and it must be written in either Groovy (build.gradle)
/// or Kotlin (build.gradle.kts).
File get appGradleFile {
final Directory appDir = hostAppGradleRoot.childDirectory('app');
final File buildGroovy = appDir.childFile('build.gradle');
final File buildKotlin = appDir.childFile('build.gradle.kts');
if (buildGroovy.existsSync() && buildKotlin.existsSync()) {
// We mimic Gradle's behavior of preferring Groovy over Kotlin when both files exist.
return buildGroovy;
}
if (buildKotlin.existsSync()) {
return buildKotlin;
}
// TODO(bartekpacia): An exception should be thrown when neither
// build.gradle nor build.gradle.kts exist, instead of falling back to the
// Groovy file. See #141180.
return buildGroovy;
}
File get appManifestFile { File get appManifestFile {
if (isUsingGradle) { if (isUsingGradle) {
...@@ -652,7 +700,7 @@ $javaGradleCompatUrl ...@@ -652,7 +700,7 @@ $javaGradleCompatUrl
} }
bool get isUsingGradle { bool get isUsingGradle {
return hostAppGradleRoot.childFile('build.gradle').existsSync(); return hostAppGradleFile.existsSync();
} }
String? get applicationId { String? get applicationId {
...@@ -671,8 +719,7 @@ $javaGradleCompatUrl ...@@ -671,8 +719,7 @@ $javaGradleCompatUrl
} }
String? get group { String? get group {
final File gradleFile = hostAppGradleRoot.childFile('build.gradle'); return firstMatchInFile(hostAppGradleFile, _groupPattern)?.group(1);
return firstMatchInFile(gradleFile, _groupPattern)?.group(1);
} }
/// The build directory where the Android artifacts are placed. /// The build directory where the Android artifacts are placed.
......
...@@ -10,13 +10,14 @@ import 'package:flutter_tools/src/base/platform.dart'; ...@@ -10,13 +10,14 @@ import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/version_range.dart'; import 'package:flutter_tools/src/base/version_range.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/fake_process_manager.dart'; import '../../src/fake_process_manager.dart';
import '../../src/fakes.dart'; import '../../src/fakes.dart';
void main() { void main() {
group('injectGradleWrapperIfNeeded', () { group('injectGradleWrapperIfNeeded', () {
late MemoryFileSystem fileSystem; late FileSystem fileSystem;
late Directory gradleWrapperDirectory; late Directory gradleWrapperDirectory;
late GradleUtils gradleUtils; late GradleUtils gradleUtils;
...@@ -386,7 +387,7 @@ OS: Mac OS X 13.2.1 aarch64 ...@@ -386,7 +387,7 @@ OS: Mac OS X 13.2.1 aarch64
); );
}); });
testWithoutContext('returns the AGP version when set', () async { testWithoutContext('returns the AGP version when set in Groovy', () async {
const String expectedVersion = '7.3.0'; const String expectedVersion = '7.3.0';
final Directory androidDirectory = fileSystem.directory('/android') final Directory androidDirectory = fileSystem.directory('/android')
..createSync(); ..createSync();
...@@ -415,6 +416,90 @@ allprojects { ...@@ -415,6 +416,90 @@ allprojects {
expectedVersion, expectedVersion,
); );
}); });
testWithoutContext('returns the AGP version when set in Kotlin', () async {
const String expectedVersion = '7.3.0';
final Directory androidDirectory = fileSystem.directory('/android')
..createSync();
androidDirectory.childFile('build.gradle.kts').writeAsStringSync('''
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:$expectedVersion")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
''');
expect(
getAgpVersion(androidDirectory, BufferLogger.test()),
expectedVersion,
);
});
testWithoutContext('prefers the AGP version when set in Groovy, ignores Kotlin', () async {
const String versionInGroovy = '7.3.0';
const String versionInKotlin = '7.4.2';
final Directory androidDirectory = fileSystem.directory('/android')
..createSync();
androidDirectory.childFile('build.gradle').writeAsStringSync('''
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:$versionInGroovy'
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
''');
androidDirectory.childFile('build.gradle.kts').writeAsStringSync('''
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:$versionInKotlin")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
''');
expect(
getAgpVersion(androidDirectory, BufferLogger.test()),
versionInGroovy,
);
});
testWithoutContext('returns null when AGP version not set', () async { testWithoutContext('returns null when AGP version not set', () async {
final Directory androidDirectory = fileSystem.directory('/android') final Directory androidDirectory = fileSystem.directory('/android')
..createSync(); ..createSync();
...@@ -703,6 +788,68 @@ include ":app" ...@@ -703,6 +788,68 @@ include ":app"
}); });
}); });
group('getGradleVersionForAndroidPlugin', () {
late FileSystem fileSystem;
late Logger testLogger;
setUp(() {
fileSystem = MemoryFileSystem.test();
testLogger = BufferLogger.test();
});
testWithoutContext('prefers build.gradle over build.gradle.kts', () async {
const String versionInGroovy = '4.0.0';
const String versionInKotlin = '7.4.2';
final Directory androidDirectory = fileSystem.directory('/android')..createSync();
androidDirectory.childFile('build.gradle').writeAsStringSync('''
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:$versionInGroovy'
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
''');
androidDirectory.childFile('build.gradle.kts').writeAsStringSync('''
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:$versionInKotlin")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
''');
expect(
getGradleVersionForAndroidPlugin(androidDirectory, testLogger),
'6.7', // as per compatibility matrix in gradle_utils.dart
);
});
});
group('validates java/AGP versions', () { group('validates java/AGP versions', () {
final List<JavaAgpTestData> testData = <JavaAgpTestData>[ final List<JavaAgpTestData> testData = <JavaAgpTestData>[
// Strictly too old Java versions for known AGP versions. // Strictly too old Java versions for known AGP versions.
......
...@@ -738,6 +738,60 @@ apply plugin: 'kotlin-android' ...@@ -738,6 +738,60 @@ apply plugin: 'kotlin-android'
XcodeProjectInterpreter: () => xcodeProjectInterpreter, XcodeProjectInterpreter: () => xcodeProjectInterpreter,
FlutterProjectFactory: () => flutterProjectFactory, FlutterProjectFactory: () => flutterProjectFactory,
}); });
testUsingContext('kotlin host app language with Gradle Kotlin DSL', () async {
final FlutterProject project = await someProject();
addAndroidGradleFile(project.directory,
kotlinDsl: true,
gradleFileContent: () {
return '''
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
''';
});
expect(project.android.isKotlin, isTrue);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
FlutterProjectFactory: () => flutterProjectFactory,
});
testUsingContext('Gradle Groovy files are preferred to Gradle Kotlin files', () async {
final FlutterProject project = await someProject();
addAndroidGradleFile(project.directory,
gradleFileContent: () {
return '''
plugins {
id "com.android.application"
id "dev.flutter.flutter-gradle-plugin"
}
''';
});
addAndroidGradleFile(project.directory,
kotlinDsl: true,
gradleFileContent: () {
return '''
plugins {
id("com.android.application")
id("kotlin-android")
id("dev.flutter.flutter-gradle-plugin")
}
''';
});
expect(project.android.isKotlin, isFalse);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
XcodeProjectInterpreter: () => xcodeProjectInterpreter,
FlutterProjectFactory: () => flutterProjectFactory,
});
}); });
group('With mocked context', () { group('With mocked context', () {
...@@ -1568,11 +1622,18 @@ void addIosProjectFile(Directory directory, {required String Function() projectF ...@@ -1568,11 +1622,18 @@ void addIosProjectFile(Directory directory, {required String Function() projectF
..writeAsStringSync(projectFileContent()); ..writeAsStringSync(projectFileContent());
} }
void addAndroidGradleFile(Directory directory, { required String Function() gradleFileContent }) { /// Adds app-level Gradle Groovy build file (build.gradle) to [directory].
///
/// If [kotlinDsl] is true, then build.gradle.kts is created instead of
/// build.gradle. It's the caller's responsibility to make sure that
/// [gradleFileContent] is consistent with the value of the [kotlinDsl] flag.
void addAndroidGradleFile(Directory directory, {
required String Function() gradleFileContent, bool kotlinDsl = false,
}) {
directory directory
.childDirectory('android') .childDirectory('android')
.childDirectory('app') .childDirectory('app')
.childFile('build.gradle') .childFile(kotlinDsl ? 'build.gradle.kts' : 'build.gradle')
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync(gradleFileContent()); ..writeAsStringSync(gradleFileContent());
} }
...@@ -1608,8 +1669,8 @@ FileSystem getFileSystemForPlatform() { ...@@ -1608,8 +1669,8 @@ FileSystem getFileSystemForPlatform() {
); );
} }
void addAndroidWithGroup(Directory directory, String id) { void addAndroidWithGroup(Directory directory, String id, {bool kotlinDsl = false}) {
directory.childDirectory('android').childFile('build.gradle') directory.childDirectory('android').childFile(kotlinDsl ? 'build.gradle.kts' : 'build.gradle')
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync(gradleFileWithGroupId(id)); ..writeAsStringSync(gradleFileWithGroupId(id));
} }
......
...@@ -147,7 +147,7 @@ void main() { ...@@ -147,7 +147,7 @@ void main() {
final ProcessResult buildApkResult = await testUnsupportedPlugin( final ProcessResult buildApkResult = await testUnsupportedPlugin(
project: project, createAndroidPluginFolder: true); project: project, createAndroidPluginFolder: true);
expect(buildApkResult.stderr.toString(), expect(buildApkResult.stderr.toString(),
isNot(contains('Please fix your settings.gradle.'))); isNot(contains('Please fix your settings.gradle')));
expect(buildApkResult, const ProcessResultMatcher()); expect(buildApkResult, const ProcessResultMatcher());
}); });
...@@ -167,7 +167,7 @@ void main() { ...@@ -167,7 +167,7 @@ void main() {
expect( expect(
buildApkResult, buildApkResult,
const ProcessResultMatcher( const ProcessResultMatcher(
stderrPattern: 'Please fix your settings.gradle.'), stderrPattern: 'Please fix your settings.gradle/settings.gradle.kts'),
); );
}); });
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment