Unverified Commit 368cd7da authored by Pranay Airan's avatar Pranay Airan Committed by GitHub

Adding support for android app bundle - Issue #17829 (#24440)

* adding support for android app bundle.

* removing the debug statement.

* fixing formatting and code review changes.

* Revert "fixing formatting and code review changes."

This reverts commit 2041d459f335242555a0b75e445343134c245494.

* Fixing code formatting issues.

* updating review comments fixing comments and spacing.

* changing and to & to rerun the CI and tests.

* updating the comment to re-run the test

updating the comment to re-run the test

* fixing the formatting.

* updating comments to re-trigger build

updating comments to re-trigger build
parent 8426910a
...@@ -44,5 +44,6 @@ Future<void> buildApk({ ...@@ -44,5 +44,6 @@ Future<void> buildApk({
project: project, project: project,
buildInfo: buildInfo, buildInfo: buildInfo,
target: target, target: target,
isBuildingBundle: false
); );
} }
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:meta/meta.dart';
import '../base/common.dart';
import '../build_info.dart';
import '../globals.dart';
import '../project.dart';
import 'android_sdk.dart';
import 'gradle.dart';
Future<void> buildAppBundle({
@required FlutterProject project,
@required String target,
BuildInfo buildInfo = BuildInfo.debug
}) async {
if (!project.android.isUsingGradle) {
throwToolExit(
'The build process for Android has changed, and the current project configuration\n'
'is no longer valid. Please consult\n\n'
'https://github.com/flutter/flutter/wiki/Upgrading-Flutter-projects-to-build-with-gradle\n\n'
'for details on how to upgrade the project.'
);
}
// Validate that we can find an android sdk.
if (androidSdk == null)
throwToolExit('No Android SDK found. Try setting the ANDROID_HOME environment variable.');
final List<String> validationResult = androidSdk.validateSdkWellFormed();
if (validationResult.isNotEmpty) {
for (String message in validationResult) {
printError(message, wrap: false);
}
throwToolExit('Try re-installing or updating your Android SDK.');
}
return buildGradleProject(
project: project,
buildInfo: buildInfo,
target: target,
isBuildingBundle: true
);
}
...@@ -12,6 +12,7 @@ import '../globals.dart'; ...@@ -12,6 +12,7 @@ import '../globals.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
import 'build_aot.dart'; import 'build_aot.dart';
import 'build_apk.dart'; import 'build_apk.dart';
import 'build_appbundle.dart';
import 'build_bundle.dart'; import 'build_bundle.dart';
import 'build_flx.dart'; import 'build_flx.dart';
import 'build_ios.dart'; import 'build_ios.dart';
...@@ -19,6 +20,7 @@ import 'build_ios.dart'; ...@@ -19,6 +20,7 @@ import 'build_ios.dart';
class BuildCommand extends FlutterCommand { class BuildCommand extends FlutterCommand {
BuildCommand({bool verboseHelp = false}) { BuildCommand({bool verboseHelp = false}) {
addSubcommand(BuildApkCommand(verboseHelp: verboseHelp)); addSubcommand(BuildApkCommand(verboseHelp: verboseHelp));
addSubcommand(BuildAppBundleCommand(verboseHelp: verboseHelp));
addSubcommand(BuildAotCommand()); addSubcommand(BuildAotCommand());
addSubcommand(BuildIOSCommand()); addSubcommand(BuildIOSCommand());
addSubcommand(BuildFlxCommand()); addSubcommand(BuildFlxCommand());
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import '../android/app_bundle.dart';
import '../project.dart';
import '../runner/flutter_command.dart' show FlutterCommandResult;
import 'build.dart';
class BuildAppBundleCommand extends BuildSubCommand {
BuildAppBundleCommand({bool verboseHelp = false}) {
usesTargetOption();
addBuildModeFlags();
usesFlavorOption();
usesPubOption();
usesBuildNumberOption();
usesBuildNameOption();
argParser
..addFlag('track-widget-creation', negatable: false, hide: !verboseHelp)
..addFlag('build-shared-library',
negatable: false,
help: 'Whether to prefer compiling to a *.so file (android only).',
)
..addOption('target-platform',
defaultsTo: 'android-arm',
allowed: <String>['android-arm', 'android-arm64']);
}
@override
final String name = 'appbundle';
@override
final String description = 'Build an Android App Bundle file from your app.\n\n'
'This command can build debug and release versions of an app bundle for your application. \'debug\' builds support '
'debugging and a quick development cycle. \'release\' builds don\'t support debugging and are '
'suitable for deploying to app stores. \n app bundle improves your app size';
@override
Future<FlutterCommandResult> runCommand() async {
await super.runCommand();
await buildAppBundle(
project: await FlutterProject.current(),
target: targetFile,
buildInfo: getBuildInfo(),
);
return null;
}
}
...@@ -361,6 +361,10 @@ class AndroidProject { ...@@ -361,6 +361,10 @@ class AndroidProject {
return fs.directory(fs.path.join(hostAppGradleRoot.path, 'app', 'build', 'outputs', 'apk')); return fs.directory(fs.path.join(hostAppGradleRoot.path, 'app', 'build', 'outputs', 'apk'));
} }
Directory get gradleAppBundleOutV1Directory {
return fs.directory(fs.path.join(hostAppGradleRoot.path, 'app', 'build', 'outputs', 'bundle'));
}
bool get isUsingGradle { bool get isUsingGradle {
return hostAppGradleRoot.childFile('build.gradle').existsSync(); return hostAppGradleRoot.childFile('build.gradle').existsSync();
} }
......
...@@ -113,35 +113,65 @@ someOtherTask ...@@ -113,35 +113,65 @@ someOtherTask
expect(project.productFlavors, <String>['free', 'paid']); expect(project.productFlavors, <String>['free', 'paid']);
}); });
test('should provide apk file name for default build types', () { test('should provide apk file name for default build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir')); final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir'),fs.directory('/some/dir'));
expect(project.apkFileFor(BuildInfo.debug), 'app-debug.apk'); expect(project.apkFileFor(BuildInfo.debug), 'app-debug.apk');
expect(project.apkFileFor(BuildInfo.profile), 'app-profile.apk'); expect(project.apkFileFor(BuildInfo.profile), 'app-profile.apk');
expect(project.apkFileFor(BuildInfo.release), 'app-release.apk'); expect(project.apkFileFor(BuildInfo.release), 'app-release.apk');
expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'unknown')), isNull); expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
}); });
test('should provide apk file name for flavored build types', () { test('should provide apk file name for flavored build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/some/dir')); final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/some/dir'),fs.directory('/some/dir'));
expect(project.apkFileFor(const BuildInfo(BuildMode.debug, 'free')), 'app-free-debug.apk'); expect(project.apkFileFor(const BuildInfo(BuildMode.debug, 'free')), 'app-free-debug.apk');
expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'paid')), 'app-paid-release.apk'); expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'paid')), 'app-paid-release.apk');
expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'unknown')), isNull); expect(project.apkFileFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
}); });
test('should provide bundle file name for default build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir'),fs.directory('/some/dir'));
expect(project.bundleFileFor(BuildInfo.debug), 'app.aab');
expect(project.bundleFileFor(BuildInfo.profile), 'app.aab');
expect(project.bundleFileFor(BuildInfo.release), 'app.aab');
expect(project.bundleFileFor(const BuildInfo(BuildMode.release, 'unknown')), 'app.aab');
});
test('should provide bundle file name for flavored build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/some/dir'),fs.directory('/some/dir'));
expect(project.bundleFileFor(const BuildInfo(BuildMode.debug, 'free')), 'app.aab');
expect(project.bundleFileFor(const BuildInfo(BuildMode.release, 'paid')), 'app.aab');
expect(project.bundleFileFor(const BuildInfo(BuildMode.release, 'unknown')), 'app.aab');
});
test('should provide assemble task name for default build types', () { test('should provide assemble task name for default build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir')); final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir'),fs.directory('/some/dir'));
expect(project.assembleTaskFor(BuildInfo.debug), 'assembleDebug'); expect(project.assembleTaskFor(BuildInfo.debug), 'assembleDebug');
expect(project.assembleTaskFor(BuildInfo.profile), 'assembleProfile'); expect(project.assembleTaskFor(BuildInfo.profile), 'assembleProfile');
expect(project.assembleTaskFor(BuildInfo.release), 'assembleRelease'); expect(project.assembleTaskFor(BuildInfo.release), 'assembleRelease');
expect(project.assembleTaskFor(const BuildInfo(BuildMode.release, 'unknown')), isNull); expect(project.assembleTaskFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
}); });
test('should provide assemble task name for flavored build types', () { test('should provide assemble task name for flavored build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/some/dir')); final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/some/dir'),fs.directory('/some/dir'));
expect(project.assembleTaskFor(const BuildInfo(BuildMode.debug, 'free')), 'assembleFreeDebug'); expect(project.assembleTaskFor(const BuildInfo(BuildMode.debug, 'free')), 'assembleFreeDebug');
expect(project.assembleTaskFor(const BuildInfo(BuildMode.release, 'paid')), 'assemblePaidRelease'); expect(project.assembleTaskFor(const BuildInfo(BuildMode.release, 'paid')), 'assemblePaidRelease');
expect(project.assembleTaskFor(const BuildInfo(BuildMode.release, 'unknown')), isNull); expect(project.assembleTaskFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
}); });
test('should respect format of the flavored build types', () { test('should respect format of the flavored build types', () {
final GradleProject project = GradleProject(<String>['debug'], <String>['randomFlavor'], fs.directory('/some/dir')); final GradleProject project = GradleProject(<String>['debug'], <String>['randomFlavor'], fs.directory('/some/dir'),fs.directory('/some/dir'));
expect(project.assembleTaskFor(const BuildInfo(BuildMode.debug, 'randomFlavor')), 'assembleRandomFlavorDebug'); expect(project.assembleTaskFor(const BuildInfo(BuildMode.debug, 'randomFlavor')), 'assembleRandomFlavorDebug');
}); });
test('bundle should provide assemble task name for default build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>[], fs.directory('/some/dir'),fs.directory('/some/dir'));
expect(project.bundleTaskFor(BuildInfo.debug), 'bundleDebug');
expect(project.bundleTaskFor(BuildInfo.profile), 'bundleProfile');
expect(project.bundleTaskFor(BuildInfo.release), 'bundleRelease');
expect(project.bundleTaskFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
});
test('bundle should provide assemble task name for flavored build types', () {
final GradleProject project = GradleProject(<String>['debug', 'profile', 'release'], <String>['free', 'paid'], fs.directory('/some/dir'),fs.directory('/some/dir'));
expect(project.bundleTaskFor(const BuildInfo(BuildMode.debug, 'free')), 'bundleFreeDebug');
expect(project.bundleTaskFor(const BuildInfo(BuildMode.release, 'paid')), 'bundlePaidRelease');
expect(project.bundleTaskFor(const BuildInfo(BuildMode.release, 'unknown')), isNull);
});
test('bundle should respect format of the flavored build types', () {
final GradleProject project = GradleProject(<String>['debug'], <String>['randomFlavor'], fs.directory('/some/dir'),fs.directory('/some/dir'));
expect(project.bundleTaskFor(const BuildInfo(BuildMode.debug, 'randomFlavor')), 'bundleRandomFlavorDebug');
});
}); });
group('Gradle local.properties', () { group('Gradle local.properties', () {
......
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