[tool][android] Allow --target-platform work properly with --debug mode (#154476)

This PR addresses an issue where the `--target-platform` flag was not being respected when building APKs in debug mode. Previously, debug builds would always include `x86` and `x64` architectures, regardless of the specified target platform. This change ensures that the `--target-platform` flag is honored across all build modes, including debug.

To achieve this, `BuildApkCommand` has been slightly changed to become responsible for list of archs that should be built in the current run,rather than just parsing arguments. Previously, this responsibility was distributed to gradle, which could be frustrating (in my opinion)

Fixes #153359
This commit is contained in:
Mikhail Novoseltsev 2024-10-01 20:24:53 +05:00 committed by GitHub
parent 6bba08cbcc
commit 0975e612c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 190 additions and 48 deletions

View File

@ -228,7 +228,6 @@ Future<void> main() async {
checkFileContains(<String>[
'flutter_embedding_debug',
'x86_debug',
'x86_64_debug',
'armeabi_v7a_debug',
'arm64_v8a_debug',

View File

@ -34,9 +34,6 @@ Future<void> main() async {
...debugAssets,
...baseApkFiles,
'lib/armeabi-v7a/libflutter.so',
// Debug mode intentionally includes `x86` and `x86_64`.
'lib/x86/libflutter.so',
'lib/x86_64/libflutter.so',
], apkFiles);
checkCollectionDoesNotContain<String>(<String>[
@ -65,9 +62,7 @@ Future<void> main() async {
...flutterAssets,
...debugAssets,
...baseApkFiles,
// Debug mode intentionally includes `x86` and `x86_64`.
'lib/x86/libflutter.so',
'lib/x86_64/libflutter.so',
], apkFiles);
checkCollectionDoesNotContain<String>(<String>[
@ -96,8 +91,6 @@ Future<void> main() async {
...flutterAssets,
...debugAssets,
...baseApkFiles,
// Debug mode intentionally includes `x86` and `x86_64`.
'lib/x86/libflutter.so',
'lib/x86_64/libflutter.so',
], apkFiles);

View File

@ -637,11 +637,6 @@ class FlutterPlugin implements Plugin<Project> {
"io.flutter:flutter_embedding_$flutterBuildMode:$engineVersion")
}
List<String> platforms = getTargetPlatforms().collect()
// Debug mode includes x86 and x64, which are commonly used in emulators.
if (flutterBuildMode == "debug" && !useLocalEngine()) {
platforms.add("android-x86")
platforms.add("android-x64")
}
platforms.each { platform ->
String arch = PLATFORM_ARCH_MAP[platform].replace("-", "_")
// Add the `libflutter.so` dependency.

View File

@ -48,15 +48,43 @@ class BuildApkCommand extends BuildSubCommand {
help: 'Generate build files used by flutter but '
'do not build any artifacts.')
..addMultiOption('target-platform',
defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'],
allowed: <String>['android-arm', 'android-arm64', 'android-x86', 'android-x64'],
// https://github.com/flutter/flutter/issues/153359 tracks debug build type support.
help:
'The target platform for which the app is compiled. Supports release but not debug build types.',
'The target platform for which the app is compiled.',
);
usesTrackWidgetCreation(verboseHelp: verboseHelp);
}
BuildMode get _buildMode {
if (boolArg('release')) {
return BuildMode.release;
} else if (boolArg('profile')) {
return BuildMode.profile;
} else if (boolArg('debug')) {
return BuildMode.debug;
} else if (boolArg('jit-release')) {
return BuildMode.jitRelease;
}
return BuildMode.release;
}
static const List<String> _kDefaultJitArchs = <String>[
'android-arm',
'android-arm64',
'android-x86',
'android-x64',
];
static const List<String> _kDefaultAotArchs = <String>[
'android-arm',
'android-arm64',
'android-x64',
];
List<String> get _targetArchs => stringsArg('target-platform').isEmpty
? switch (_buildMode) {
BuildMode.release || BuildMode.profile => _kDefaultAotArchs,
BuildMode.debug || BuildMode.jitRelease => _kDefaultJitArchs,
}
: stringsArg('target-platform');
@override
final String name = 'apk';
@ -81,46 +109,20 @@ class BuildApkCommand extends BuildSubCommand {
@override
Future<CustomDimensions> get usageValues async {
String buildMode;
if (boolArg('release')) {
buildMode = 'release';
} else if (boolArg('debug')) {
buildMode = 'debug';
} else if (boolArg('profile')) {
buildMode = 'profile';
} else {
// The build defaults to release.
buildMode = 'release';
}
return CustomDimensions(
commandBuildApkTargetPlatform: stringsArg('target-platform').join(','),
commandBuildApkBuildMode: buildMode,
commandBuildApkTargetPlatform: _targetArchs.join(','),
commandBuildApkBuildMode: _buildMode.cliName,
commandBuildApkSplitPerAbi: boolArg('split-per-abi'),
);
}
@override
Future<Event> unifiedAnalyticsUsageValues(String commandPath) async {
final String buildMode;
if (boolArg('release')) {
buildMode = 'release';
} else if (boolArg('debug')) {
buildMode = 'debug';
} else if (boolArg('profile')) {
buildMode = 'profile';
} else {
// The build defaults to release.
buildMode = 'release';
}
return Event.commandUsageValues(
workflow: commandPath,
commandHasTerminal: hasTerminal,
buildApkTargetPlatform: stringsArg('target-platform').join(','),
buildApkBuildMode: buildMode,
buildApkTargetPlatform: _targetArchs.join(','),
buildApkBuildMode: _buildMode.cliName,
buildApkSplitPerAbi: boolArg('split-per-abi'),
);
}
@ -131,10 +133,11 @@ class BuildApkCommand extends BuildSubCommand {
exitWithNoSdkMessage();
}
final BuildInfo buildInfo = await getBuildInfo();
final AndroidBuildInfo androidBuildInfo = AndroidBuildInfo(
buildInfo,
splitPerAbi: boolArg('split-per-abi'),
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
targetArchs: _targetArchs.map<AndroidArch>(getAndroidArchForName),
);
validateBuild(androidBuildInfo);
displayNullSafetyMode(androidBuildInfo.buildInfo);

View File

@ -48,8 +48,9 @@ void main() {
testUsingContext('indicate the default target platforms', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
await runBuildApkCommand(projectPath);
// Without buildMode flag.
await runBuildApkCommand(projectPath);
expect(
fakeAnalytics.sentEvents,
contains(
@ -62,6 +63,157 @@ void main() {
),
),
);
await runBuildApkCommand(projectPath, arguments: <String>['--debug']);
expect(
fakeAnalytics.sentEvents,
contains(
Event.commandUsageValues(
workflow: 'apk',
commandHasTerminal: false,
buildApkTargetPlatform: 'android-arm,android-arm64,android-x86,android-x64',
buildApkBuildMode: 'debug',
buildApkSplitPerAbi: false,
),
),
);
await runBuildApkCommand(projectPath, arguments: <String>['--jit-release']);
expect(
fakeAnalytics.sentEvents,
contains(
Event.commandUsageValues(
workflow: 'apk',
commandHasTerminal: false,
buildApkTargetPlatform: 'android-arm,android-arm64,android-x86,android-x64',
buildApkBuildMode: 'jit_release',
buildApkSplitPerAbi: false,
),
),
);
await runBuildApkCommand(projectPath, arguments: <String>['--profile']);
expect(
fakeAnalytics.sentEvents,
contains(
Event.commandUsageValues(
workflow: 'apk',
commandHasTerminal: false,
buildApkTargetPlatform: 'android-arm,android-arm64,android-x64',
buildApkBuildMode: 'profile',
buildApkSplitPerAbi: false,
),
),
);
await runBuildApkCommand(projectPath, arguments: <String>['--release']);
expect(
fakeAnalytics.sentEvents,
contains(
Event.commandUsageValues(
workflow: 'apk',
commandHasTerminal: false,
buildApkTargetPlatform: 'android-arm,android-arm64,android-x64',
buildApkBuildMode: 'release',
buildApkSplitPerAbi: false,
),
),
);
}, overrides: <Type, Generator>{
AndroidBuilder: () => FakeAndroidBuilder(),
Analytics: () => fakeAnalytics,
});
testUsingContext('Each build mode respects --target-platform', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
// Without buildMode flag.
await runBuildApkCommand(
projectPath,
arguments: <String>['--target-platform=android-arm'],
);
expect(
fakeAnalytics.sentEvents,
contains(
Event.commandUsageValues(
workflow: 'apk',
commandHasTerminal: false,
buildApkTargetPlatform: 'android-arm',
buildApkBuildMode: 'release',
buildApkSplitPerAbi: false,
),
),
);
await runBuildApkCommand(
projectPath,
arguments: <String>['--debug', '--target-platform=android-arm'],
);
expect(
fakeAnalytics.sentEvents,
contains(
Event.commandUsageValues(
workflow: 'apk',
commandHasTerminal: false,
buildApkTargetPlatform: 'android-arm',
buildApkBuildMode: 'debug',
buildApkSplitPerAbi: false,
),
),
);
await runBuildApkCommand(
projectPath,
arguments: <String>['--release', '--target-platform=android-arm'],
);
expect(
fakeAnalytics.sentEvents,
contains(
Event.commandUsageValues(
workflow: 'apk',
commandHasTerminal: false,
buildApkTargetPlatform: 'android-arm',
buildApkBuildMode: 'release',
buildApkSplitPerAbi: false,
),
),
);
await runBuildApkCommand(
projectPath,
arguments: <String>['--profile', '--target-platform=android-arm'],
);
expect(
fakeAnalytics.sentEvents,
contains(
Event.commandUsageValues(
workflow: 'apk',
commandHasTerminal: false,
buildApkTargetPlatform: 'android-arm',
buildApkBuildMode: 'profile',
buildApkSplitPerAbi: false,
),
),
);
await runBuildApkCommand(
projectPath,
arguments: <String>['--jit-release', '--target-platform=android-arm'],
);
expect(
fakeAnalytics.sentEvents,
contains(
Event.commandUsageValues(
workflow: 'apk',
commandHasTerminal: false,
buildApkTargetPlatform: 'android-arm',
buildApkBuildMode: 'jit_release',
buildApkSplitPerAbi: false,
),
),
);
}, overrides: <Type, Generator>{
AndroidBuilder: () => FakeAndroidBuilder(),
Analytics: () => fakeAnalytics,