Build AAR for all build variants by default (#44797)

This commit is contained in:
Emmanuel Garcia 2019-11-13 13:27:10 -08:00 committed by GitHub
parent 66821916dc
commit 0019599411
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 292 additions and 129 deletions

View file

@ -26,9 +26,9 @@ abstract class AndroidBuilder {
/// Builds an AAR artifact.
Future<void> buildAar({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required Set<AndroidBuildInfo> androidBuildInfo,
@required String target,
@required String outputDir,
@required String outputDirectoryPath,
});
/// Builds an APK artifact.
@ -54,23 +54,32 @@ class _AndroidBuilderImpl extends AndroidBuilder {
@override
Future<void> buildAar({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required Set<AndroidBuildInfo> androidBuildInfo,
@required String target,
@required String outputDir,
@required String outputDirectoryPath,
}) async {
try {
Directory outputDirectory =
fs.directory(outputDir ?? project.android.buildDirectory);
fs.directory(outputDirectoryPath ?? project.android.buildDirectory);
if (project.isModule) {
// Module projects artifacts are located in `build/host`.
outputDirectory = outputDirectory.childDirectory('host');
}
await buildGradleAar(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
outputDir: outputDirectory,
printHowToConsumeAaar: true,
for (AndroidBuildInfo androidBuildInfo in androidBuildInfo) {
await buildGradleAar(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
outputDirectory: outputDirectory,
);
}
printHowToConsumeAar(
buildModes: androidBuildInfo
.map<String>((AndroidBuildInfo androidBuildInfo) {
return androidBuildInfo.buildInfo.modeName;
}).toSet(),
androidPackage: project.manifest.androidPackage,
repoDirectory: getRepoDirectory(outputDirectory),
);
} finally {
androidSdk.reinitialize();

View file

@ -57,7 +57,6 @@ Directory getBundleDirectory(FlutterProject project) {
/// The directory where the repo is generated.
/// Only applicable to AARs.
@visibleForTesting
Directory getRepoDirectory(Directory buildDirectory) {
return buildDirectory
.childDirectory('outputs')
@ -474,20 +473,17 @@ Future<void> buildGradleApp({
///
/// * [project] is typically [FlutterProject.current()].
/// * [androidBuildInfo] is the build configuration.
/// * [target] is the target dart entrypoint. Typically, `lib/main.dart`.
/// * [outputDir] is the destination of the artifacts,
Future<void> buildGradleAar({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
@required Directory outputDir,
@required bool printHowToConsumeAaar,
@required Directory outputDirectory,
}) async {
assert(project != null);
assert(androidBuildInfo != null);
assert(target != null);
assert(outputDir != null);
assert(printHowToConsumeAaar != null);
assert(androidBuildInfo != null);
assert(outputDirectory != null);
if (androidSdk == null) {
exitWithNoSdkMessage();
@ -516,13 +512,14 @@ Future<void> buildGradleAar({
gradleUtils.getExecutable(project),
'-I=$initScript',
'-Pflutter-root=$flutterRoot',
'-Poutput-dir=${outputDir.path}',
'-Poutput-dir=${outputDirectory.path}',
'-Pis-plugin=${manifest.isPlugin}',
];
if (target != null && target.isNotEmpty) {
command.add('-Ptarget=$target');
}
if (androidBuildInfo.targetArchs.isNotEmpty) {
final String targetPlatforms = androidBuildInfo.targetArchs
.map(getPlatformNameForAndroidArch).join(',');
@ -567,7 +564,7 @@ Future<void> buildGradleAar({
exitCode: exitCode,
);
}
final Directory repoDirectory = getRepoDirectory(outputDir);
final Directory repoDirectory = getRepoDirectory(outputDirectory);
if (!repoDirectory.existsSync()) {
printStatus(result.stdout, wrap: false);
printError(result.stderr, wrap: false);
@ -580,24 +577,17 @@ Future<void> buildGradleAar({
'$successMark Built ${fs.path.relative(repoDirectory.path)}.',
color: TerminalColor.green,
);
if (printHowToConsumeAaar) {
_printHowToConsumeAar(
buildMode: androidBuildInfo.buildInfo.modeName,
androidPackage: project.manifest.androidPackage,
repoPath: repoDirectory.path,
);
}
}
/// Prints how to consume the AAR from a host app.
void _printHowToConsumeAar({
@required String buildMode,
void printHowToConsumeAar({
@required Set<String> buildModes,
@required String androidPackage,
@required String repoPath,
@required Directory repoDirectory,
}) {
assert(buildMode != null);
assert(buildModes != null && buildModes.isNotEmpty);
assert(androidPackage != null);
assert(repoPath != null);
assert(repoDirectory != null);
printStatus('''
@ -607,20 +597,42 @@ ${terminal.bolden('Consuming the Module')}
repositories {
maven {
url '$repoPath'
url '${repoDirectory.path}'
}
maven {
url 'http://download.flutter.io'
}
}
3. Make the host app depend on the $buildMode module:
3. Make the host app depend on the Flutter module:
dependencies {
${buildMode}Implementation '$androidPackage:flutter_$buildMode:1.0'
dependencies {''');
for (String buildMode in buildModes) {
printStatus('''
${buildMode}Implementation '$androidPackage:flutter_$buildMode:1.0''');
}
printStatus('''
}
''');
if (buildModes.contains('profile')) {
printStatus('''
4. Add the `profile` build type:
android {
buildTypes {
profile {
initWith debug
}
}
}
''');
}
To learn more, visit https://flutter.dev/go/build-aar''');
printStatus('To learn more, visit https://flutter.dev/go/build-aar''');
}
String _hex(List<int> bytes) {
@ -705,8 +717,7 @@ Future<void> buildPluginsAsAar(
),
),
target: '',
outputDir: buildDirectory,
printHowToConsumeAaar: false,
outputDirectory: buildDirectory,
);
} on ToolExit {
// Log the entire plugin entry in `.flutter-plugins` since it

View file

@ -21,7 +21,7 @@ import 'build_web.dart';
class BuildCommand extends FlutterCommand {
BuildCommand({bool verboseHelp = false}) {
addSubcommand(BuildAarCommand(verboseHelp: verboseHelp));
addSubcommand(BuildAarCommand());
addSubcommand(BuildApkCommand(verboseHelp: verboseHelp));
addSubcommand(BuildAppBundleCommand(verboseHelp: verboseHelp));
addSubcommand(BuildAotCommand(verboseHelp: verboseHelp));

View file

@ -5,6 +5,7 @@
import 'dart:async';
import '../android/android_builder.dart';
import '../base/common.dart';
import '../base/os.dart';
import '../build_info.dart';
import '../cache.dart';
@ -14,18 +15,35 @@ import '../runner/flutter_command.dart' show FlutterCommandResult;
import 'build.dart';
class BuildAarCommand extends BuildSubCommand {
BuildAarCommand({bool verboseHelp = false}) {
addBuildModeFlags(verboseHelp: verboseHelp);
BuildAarCommand() {
argParser
..addFlag(
'debug',
defaultsTo: true,
help: 'Build a debug version of the current project.',
)
..addFlag(
'profile',
defaultsTo: true,
help: 'Build a version of the current project specialized for performance profiling.',
)
..addFlag(
'release',
defaultsTo: true,
help: 'Build a release version of the current project.',
);
usesFlavorOption();
usesPubOption();
argParser
..addMultiOption('target-platform',
..addMultiOption(
'target-platform',
splitCommas: true,
defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'],
allowed: <String>['android-arm', 'android-arm64', 'android-x86', 'android-x64'],
help: 'The target platform for which the project is compiled.',
)
..addOption('output-dir',
..addOption(
'output-dir',
help: 'The absolute path to the directory where the repository is generated.'
'By default, this is \'<current-directory>android/build\'. ',
);
@ -61,21 +79,35 @@ class BuildAarCommand extends BuildSubCommand {
@override
final String description = 'Build a repository containing an AAR and a POM file.\n\n'
'The POM file is used to include the dependencies that the AAR was compiled against.\n\n'
'By default, AARs are built for `release`, `debug` and `profile`.\n'
'The POM file is used to include the dependencies that the AAR was compiled against.\n'
'To learn more about how to use these artifacts, see '
'https://docs.gradle.org/current/userguide/repository_types.html#sub:maven_local';
'https://flutter.dev/go/build-aar';
@override
Future<FlutterCommandResult> runCommand() async {
final BuildInfo buildInfo = getBuildInfo();
final AndroidBuildInfo androidBuildInfo = AndroidBuildInfo(buildInfo,
targetArchs: argResults['target-platform'].map<AndroidArch>(getAndroidArchForName));
final Set<AndroidBuildInfo> androidBuildInfo = <AndroidBuildInfo>{};
final Iterable<AndroidArch> targetArchitectures = argResults['target-platform']
.map<AndroidArch>(getAndroidArchForName);
for (String buildMode in const <String>['debug', 'profile', 'release']) {
if (argResults[buildMode]) {
androidBuildInfo.add(
AndroidBuildInfo(
BuildInfo(BuildMode.fromName(buildMode), argResults['flavor']),
targetArchs: targetArchitectures,
)
);
}
}
if (androidBuildInfo.isEmpty) {
throwToolExit('Please specify a build mode and try again.');
}
await androidBuilder.buildAar(
project: _getProject(),
target: '', // Not needed because this command only builds Android's code.
androidBuildInfo: androidBuildInfo,
outputDir: argResults['output-dir'],
outputDirectoryPath: argResults['output-dir'],
);
return null;
}

View file

@ -1618,79 +1618,6 @@ plugin2=${plugin2.path}
ProcessManager: () => mockProcessManager,
});
testUsingContext('indicates how to consume an AAR when printHowToConsumeAaar is true', () async {
final File manifestFile = fs.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
manifestFile.writeAsStringSync('''
flutter:
module:
androidPackage: com.example.test
'''
);
fs.file('.android/gradlew').createSync(recursive: true);
fs.file('.android/gradle.properties')
.writeAsStringSync('irrelevant');
fs.file('.android/build.gradle')
.createSync(recursive: true);
// Let any process start. Assert after.
when(mockProcessManager.run(
any,
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
)).thenAnswer((_) async => ProcessResult(1, 0, '', ''));
fs.directory('build/outputs/repo').createSync(recursive: true);
await buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(BuildInfo(BuildMode.release, null)),
project: FlutterProject.current(),
outputDir: fs.directory('build/'),
target: '',
printHowToConsumeAaar: true,
);
final BufferLogger logger = context.get<Logger>();
expect(
logger.statusText,
contains('Built build/outputs/repo'),
);
expect(
logger.statusText,
contains('''
Consuming the Module
1. Open <host>/app/build.gradle
2. Ensure you have the repositories configured, otherwise add them:
repositories {
maven {
url 'build/outputs/repo'
}
maven {
url 'http://download.flutter.io'
}
}
3. Make the host app depend on the release module:
dependencies {
releaseImplementation 'com.example.test:flutter_release:1.0'
}
To learn more, visit https://flutter.dev/go/build-aar'''));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
AndroidStudio: () => mockAndroidStudio,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('doesn\'t indicate how to consume an AAR when printHowToConsumeAaar is false', () async {
final File manifestFile = fs.file('pubspec.yaml');
manifestFile.createSync(recursive: true);
@ -1721,9 +1648,8 @@ To learn more, visit https://flutter.dev/go/build-aar'''));
await buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(BuildInfo(BuildMode.release, null)),
project: FlutterProject.current(),
outputDir: fs.directory('build/'),
outputDirectory: fs.directory('build/'),
target: '',
printHowToConsumeAaar: false,
);
final BufferLogger logger = context.get<Logger>();
@ -1885,9 +1811,8 @@ To learn more, visit https://flutter.dev/go/build-aar'''));
await buildGradleAar(
androidBuildInfo: const AndroidBuildInfo(BuildInfo(BuildMode.release, null)),
project: FlutterProject.current(),
outputDir: fs.directory('build/'),
outputDirectory: fs.directory('build/'),
target: '',
printHowToConsumeAaar: false,
);
final List<String> actualGradlewCall = verify(
@ -1913,6 +1838,192 @@ To learn more, visit https://flutter.dev/go/build-aar'''));
ProcessManager: () => mockProcessManager,
});
});
group('printHowToConsumeAar', () {
testUsingContext('stdout contains release, debug and profile', () async {
printHowToConsumeAar(
buildModes: const <String>{'release', 'debug', 'profile'},
androidPackage: 'com.mycompany',
repoDirectory: fs.directory('build/'),
);
final BufferLogger logger = context.get<Logger>();
expect(
logger.statusText,
contains(
'\n'
'Consuming the Module\n'
' 1. Open <host>/app/build.gradle\n'
' 2. Ensure you have the repositories configured, otherwise add them:\n'
'\n'
' repositories {\n'
' maven {\n'
' url \'build/\'\n'
' }\n'
' maven {\n'
' url \'http://download.flutter.io\'\n'
' }\n'
' }\n'
'\n'
' 3. Make the host app depend on the Flutter module:\n'
'\n'
' dependencies {\n'
' releaseImplementation \'com.mycompany:flutter_release:1.0\n'
' debugImplementation \'com.mycompany:flutter_debug:1.0\n'
' profileImplementation \'com.mycompany:flutter_profile:1.0\n'
' }\n'
'\n'
'\n'
' 4. Add the `profile` build type:\n'
'\n'
' android {\n'
' buildTypes {\n'
' profile {\n'
' initWith debug\n'
' }\n'
' }\n'
' }\n'
'\n'
'To learn more, visit https://flutter.dev/go/build-aar\n'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
Platform: () => fakePlatform('android'),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('stdout contains release', () async {
printHowToConsumeAar(
buildModes: const <String>{'release'},
androidPackage: 'com.mycompany',
repoDirectory: fs.directory('build/'),
);
final BufferLogger logger = context.get<Logger>();
expect(
logger.statusText,
contains(
'\n'
'Consuming the Module\n'
' 1. Open <host>/app/build.gradle\n'
' 2. Ensure you have the repositories configured, otherwise add them:\n'
'\n'
' repositories {\n'
' maven {\n'
' url \'build/\'\n'
' }\n'
' maven {\n'
' url \'http://download.flutter.io\'\n'
' }\n'
' }\n'
'\n'
' 3. Make the host app depend on the Flutter module:\n'
'\n'
' dependencies {\n'
' releaseImplementation \'com.mycompany:flutter_release:1.0\n'
' }\n'
'\n'
'To learn more, visit https://flutter.dev/go/build-aar\n'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
Platform: () => fakePlatform('android'),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('stdout contains debug', () async {
printHowToConsumeAar(
buildModes: const <String>{'debug'},
androidPackage: 'com.mycompany',
repoDirectory: fs.directory('build/'),
);
final BufferLogger logger = context.get<Logger>();
expect(
logger.statusText,
contains(
'\n'
'Consuming the Module\n'
' 1. Open <host>/app/build.gradle\n'
' 2. Ensure you have the repositories configured, otherwise add them:\n'
'\n'
' repositories {\n'
' maven {\n'
' url \'build/\'\n'
' }\n'
' maven {\n'
' url \'http://download.flutter.io\'\n'
' }\n'
' }\n'
'\n'
' 3. Make the host app depend on the Flutter module:\n'
'\n'
' dependencies {\n'
' debugImplementation \'com.mycompany:flutter_debug:1.0\n'
' }\n'
'\n'
'To learn more, visit https://flutter.dev/go/build-aar\n'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
Platform: () => fakePlatform('android'),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('stdout contains profile', () async {
printHowToConsumeAar(
buildModes: const <String>{'profile'},
androidPackage: 'com.mycompany',
repoDirectory: fs.directory('build/'),
);
final BufferLogger logger = context.get<Logger>();
expect(
logger.statusText,
contains(
'\n'
'Consuming the Module\n'
' 1. Open <host>/app/build.gradle\n'
' 2. Ensure you have the repositories configured, otherwise add them:\n'
'\n'
' repositories {\n'
' maven {\n'
' url \'build/\'\n'
' }\n'
' maven {\n'
' url \'http://download.flutter.io\'\n'
' }\n'
' }\n'
'\n'
' 3. Make the host app depend on the Flutter module:\n'
'\n'
' dependencies {\n'
' profileImplementation \'com.mycompany:flutter_profile:1.0\n'
' }\n'
'\n'
'\n'
' 4. Add the `profile` build type:\n'
'\n'
' android {\n'
' buildTypes {\n'
' profile {\n'
' initWith debug\n'
' }\n'
' }\n'
' }\n'
'\n'
'To learn more, visit https://flutter.dev/go/build-aar\n'
)
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
Platform: () => fakePlatform('android'),
ProcessManager: () => FakeProcessManager.any(),
});
});
}
/// Generates a fake app bundle at the location [directoryName]/[fileName].

View file

@ -13,9 +13,9 @@ class FakeAndroidBuilder implements AndroidBuilder {
@override
Future<void> buildAar({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required Set<AndroidBuildInfo> androidBuildInfo,
@required String target,
@required String outputDir,
@required String outputDirectoryPath,
}) async {}
@override