Skip to content

Commit 55502fc

Browse files
authored
Add vmservice for android build options (#123034)
flutter/flutter#120408
1 parent 42fb0b2 commit 55502fc

19 files changed

+409
-73
lines changed

packages/flutter_tools/gradle/flutter.gradle

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,28 @@ class FlutterPlugin implements Plugin<Project> {
695695
}
696696
}
697697

698+
// Add a task that can be called on flutter projects that prints the available build variants
699+
// in gradle.
700+
//
701+
// This task prints variants in this format:
702+
//
703+
// BuildVariant: debug
704+
// BuildVariant: release
705+
// BuildVariant: profile
706+
//
707+
// Format of the output of this task is used by `AndroidProject.getBuildVariants`.
708+
private static void addTaskForPrintBuildVariants(Project project) {
709+
// Warning: The name of this task is used by `AndroidProject.getBuildVariants`.
710+
project.tasks.register("printBuildVariants") {
711+
description "Prints out all build variants for this Android project"
712+
doLast {
713+
project.android.applicationVariants.all { variant ->
714+
println "BuildVariant: ${variant.name}";
715+
}
716+
}
717+
}
718+
}
719+
698720
/**
699721
* Returns a Flutter build mode suitable for the specified Android buildType.
700722
*
@@ -867,7 +889,9 @@ class FlutterPlugin implements Plugin<Project> {
867889
if (project.hasProperty('validate-deferred-components')) {
868890
validateDeferredComponentsValue = project.property('validate-deferred-components').toBoolean()
869891
}
892+
870893
addTaskForJavaVersion(project)
894+
addTaskForPrintBuildVariants(project)
871895
def targetPlatforms = getTargetPlatforms()
872896
def addFlutterDeps = { variant ->
873897
if (shouldSplitPerAbi()) {

packages/flutter_tools/lib/src/android/android_builder.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,7 @@ abstract class AndroidBuilder {
3939
bool deferredComponentsEnabled = false,
4040
bool configOnly = false,
4141
});
42+
43+
/// Returns a list of available build variant from the Android project.
44+
Future<List<String>> getBuildVariants({required FlutterProject project});
4245
}

packages/flutter_tools/lib/src/android/android_sdk.dart

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class AndroidSdk {
4040
reinitialize();
4141
}
4242

43-
static const String _javaHomeEnvironmentVariable = 'JAVA_HOME';
43+
static const String javaHomeEnvironmentVariable = 'JAVA_HOME';
4444
static const String _javaExecutable = 'java';
4545

4646
/// The Android SDK root directory.
@@ -462,10 +462,44 @@ class AndroidSdk {
462462
return versionString.split('_').first;
463463
}
464464

465-
/// Finds the java binary that is used for all operations across the tool.
465+
/// A value that would be appropriate to use as JAVA_HOME.
466466
///
467-
/// First try Java bundled with Android Studio, then sniff JAVA_HOME, then fallback to PATH.
467+
/// This method considers jdk in the following order:
468+
/// * the JDK bundled with Android Studio, if one is found;
469+
/// * the JAVA_HOME in the ambient environment, if set;
470+
String? get javaHome {
471+
return findJavaHome(
472+
androidStudio: globals.androidStudio,
473+
fileSystem: globals.fs,
474+
operatingSystemUtils: globals.os,
475+
platform: globals.platform,
476+
);
477+
}
478+
479+
480+
static String? findJavaHome({
481+
required AndroidStudio? androidStudio,
482+
required FileSystem fileSystem,
483+
required OperatingSystemUtils operatingSystemUtils,
484+
required Platform platform,
485+
}) {
486+
if (androidStudio?.javaPath != null) {
487+
globals.printTrace("Using Android Studio's java.");
488+
return androidStudio!.javaPath!;
489+
}
490+
491+
final String? javaHomeEnv = platform.environment[javaHomeEnvironmentVariable];
492+
if (javaHomeEnv != null) {
493+
globals.printTrace('Using JAVA_HOME from environment valuables.');
494+
return javaHomeEnv;
495+
}
496+
return null;
497+
}
498+
499+
/// Finds the java binary that is used for all operations across the tool.
468500
///
501+
/// This comes from [findJavaHome] if that method returns non-null;
502+
/// otherwise, it gets from searching PATH.
469503
// TODO(andrewkolos): To prevent confusion when debugging Android-related
470504
// issues (see https://github.com/flutter/flutter/issues/122609 for an example),
471505
// this logic should be consistently followed by any Java-dependent operation
@@ -479,17 +513,15 @@ class AndroidSdk {
479513
required OperatingSystemUtils operatingSystemUtils,
480514
required Platform platform,
481515
}) {
482-
if (androidStudio?.javaPath != null) {
483-
globals.printTrace("Using Android Studio's java.");
484-
return fileSystem.path.join(androidStudio!.javaPath!, 'bin', 'java');
485-
}
516+
final String? javaHome = findJavaHome(
517+
androidStudio: androidStudio,
518+
fileSystem: fileSystem,
519+
operatingSystemUtils: operatingSystemUtils,
520+
platform: platform,
521+
);
486522

487-
final String? javaHomeEnv =
488-
platform.environment[_javaHomeEnvironmentVariable];
489-
if (javaHomeEnv != null) {
490-
// Trust JAVA_HOME.
491-
globals.printTrace('Using JAVA_HOME.');
492-
return fileSystem.path.join(javaHomeEnv, 'bin', 'java');
523+
if (javaHome != null) {
524+
return fileSystem.path.join(javaHome, 'bin', 'java');
493525
}
494526

495527
// Fallback to PATH based lookup.
@@ -528,8 +560,8 @@ class AndroidSdk {
528560
);
529561
if (javaBinary != null && globals.platform.environment['PATH'] != null) {
530562
_sdkManagerEnv!['PATH'] = globals.fs.path.dirname(javaBinary) +
531-
globals.os.pathVarSeparator +
532-
globals.platform.environment['PATH']!;
563+
globals.os.pathVarSeparator +
564+
globals.platform.environment['PATH']!;
533565
}
534566
}
535567
return _sdkManagerEnv!;

packages/flutter_tools/lib/src/android/gradle.dart

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,28 @@ import '../build_info.dart';
2626
import '../cache.dart';
2727
import '../convert.dart';
2828
import '../flutter_manifest.dart';
29+
import '../globals.dart' as globals;
2930
import '../project.dart';
3031
import '../reporting/reporting.dart';
3132
import 'android_builder.dart';
32-
import 'android_studio.dart';
33+
import 'android_sdk.dart';
3334
import 'gradle_errors.dart';
3435
import 'gradle_utils.dart';
3536
import 'migrations/top_level_gradle_build_file_migration.dart';
3637
import 'multidex.dart';
3738

39+
/// The regex to grab variant names from printVariants gradle task
40+
///
41+
/// The task is defined in flutter/packages/flutter_tools/gradle/flutter.gradle.
42+
///
43+
/// The expected output from the task should be similar to:
44+
///
45+
/// BuildVariant: debug
46+
/// BuildVariant: release
47+
/// BuildVariant: profile
48+
final RegExp _kBuildVariantRegex = RegExp('^BuildVariant: (?<$_kBuildVariantRegexGroupName>.*)\$');
49+
const String _kBuildVariantRegexGroupName = 'variant';
50+
3851
/// The directory where the APK artifact is generated.
3952
Directory getApkDirectory(FlutterProject project) {
4053
return project.isModule
@@ -397,13 +410,14 @@ class AndroidGradleBuilder implements AndroidBuilder {
397410
..start();
398411
int exitCode = 1;
399412
try {
413+
final String? javaHome = globals.androidSdk?.javaHome;
400414
exitCode = await _processUtils.stream(
401415
command,
402416
workingDirectory: project.android.hostAppGradleRoot.path,
403417
allowReentrantFlutter: true,
404418
environment: <String, String>{
405-
if (javaPath != null)
406-
'JAVA_HOME': javaPath!,
419+
if (javaHome != null)
420+
AndroidSdk.javaHomeEnvironmentVariable: javaHome,
407421
},
408422
mapFunction: consumeLog,
409423
);
@@ -666,13 +680,14 @@ class AndroidGradleBuilder implements AndroidBuilder {
666680
..start();
667681
RunResult result;
668682
try {
683+
final String? javaHome = globals.androidSdk?.javaHome;
669684
result = await _processUtils.run(
670685
command,
671686
workingDirectory: project.android.hostAppGradleRoot.path,
672687
allowReentrantFlutter: true,
673688
environment: <String, String>{
674-
if (javaPath != null)
675-
'JAVA_HOME': javaPath!,
689+
if (javaHome != null)
690+
AndroidSdk.javaHomeEnvironmentVariable: javaHome,
676691
},
677692
);
678693
} finally {
@@ -702,6 +717,51 @@ class AndroidGradleBuilder implements AndroidBuilder {
702717
color: TerminalColor.green,
703718
);
704719
}
720+
721+
@override
722+
Future<List<String>> getBuildVariants({required FlutterProject project}) async {
723+
final Status status = _logger.startProgress(
724+
"Running Gradle task 'printBuildVariants'...",
725+
);
726+
final List<String> command = <String>[
727+
_gradleUtils.getExecutable(project),
728+
'-q', // suppresses gradle output.
729+
'printBuildVariants',
730+
];
731+
732+
final Stopwatch sw = Stopwatch()
733+
..start();
734+
RunResult result;
735+
try {
736+
final String? javaHome = globals.androidSdk?.javaHome;
737+
result = await _processUtils.run(
738+
command,
739+
workingDirectory: project.android.hostAppGradleRoot.path,
740+
allowReentrantFlutter: true,
741+
environment: <String, String>{
742+
if (javaHome != null)
743+
AndroidSdk.javaHomeEnvironmentVariable: javaHome,
744+
},
745+
);
746+
} finally {
747+
status.stop();
748+
}
749+
_usage.sendTiming('print', 'android build variants', sw.elapsed);
750+
751+
if (result.exitCode != 0) {
752+
_logger.printStatus(result.stdout, wrap: false);
753+
_logger.printError(result.stderr, wrap: false);
754+
return const <String>[];
755+
}
756+
final List<String> options = <String>[];
757+
for (final String line in LineSplitter.split(result.stdout)) {
758+
final RegExpMatch? match = _kBuildVariantRegex.firstMatch(line);
759+
if (match != null) {
760+
options.add(match.namedGroup(_kBuildVariantRegexGroupName)!);
761+
}
762+
}
763+
return options;
764+
}
705765
}
706766

707767
/// Prints how to consume the AAR from a host app.

packages/flutter_tools/lib/src/android/gradle_errors.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import '../base/terminal.dart';
1111
import '../globals.dart' as globals;
1212
import '../project.dart';
1313
import '../reporting/reporting.dart';
14+
import 'android_sdk.dart';
1415
import 'android_studio.dart';
1516
import 'gradle_utils.dart';
1617
import 'multidex.dart';
@@ -379,7 +380,7 @@ final GradleHandledError flavorUndefinedHandler = GradleHandledError(
379380
workingDirectory: project.android.hostAppGradleRoot.path,
380381
environment: <String, String>{
381382
if (javaPath != null)
382-
'JAVA_HOME': javaPath!,
383+
AndroidSdk.javaHomeEnvironmentVariable: javaPath!,
383384
},
384385
);
385386
// Extract build types and product flavors.

packages/flutter_tools/lib/src/flutter_cache.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'dart:async';
77
import 'package:meta/meta.dart';
88
import 'package:package_config/package_config.dart';
99

10+
import 'android/android_sdk.dart';
1011
import 'android/android_studio.dart';
1112
import 'base/common.dart';
1213
import 'base/error_handling_io.dart';
@@ -425,7 +426,7 @@ class AndroidMavenArtifacts extends ArtifactSet {
425426
],
426427
environment: <String, String>{
427428
if (javaPath != null)
428-
'JAVA_HOME': javaPath!,
429+
AndroidSdk.javaHomeEnvironmentVariable: javaPath!,
429430
},
430431
);
431432
if (processResult.exitCode != 0) {

packages/flutter_tools/lib/src/project.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:xml/xml.dart';
77
import 'package:yaml/yaml.dart';
88

99
import '../src/convert.dart';
10+
import 'android/android_builder.dart';
1011
import 'android/gradle_utils.dart' as gradle;
1112
import 'base/common.dart';
1213
import 'base/error_handling_io.dart';
@@ -474,6 +475,13 @@ class AndroidProject extends FlutterProjectPlatform {
474475
/// Returns true if the current version of the Gradle plugin is supported.
475476
late final bool isSupportedVersion = _computeSupportedVersion();
476477

478+
Future<List<String>> getBuildVariants() async {
479+
if (!existsSync() || androidBuilder == null) {
480+
return const <String>[];
481+
}
482+
return androidBuilder!.getBuildVariants(project: parent);
483+
}
484+
477485
bool _computeSupportedVersion() {
478486
final FileSystem fileSystem = hostAppGradleRoot.fileSystem;
479487
final File plugin = hostAppGradleRoot.childFile(

0 commit comments

Comments
 (0)