Unverified Commit a9c31eca authored by Zachary Anderson's avatar Zachary Anderson Committed by GitHub

Revert "Add multidex flag and automatic multidex support (#90944)" (#91791)

This reverts commit 1d9edde0.
parent 158939a8
......@@ -215,38 +215,6 @@ class FlutterPlugin implements Plugin<Project> {
}
}
if (project.hasProperty("multidex-enabled") &&
project.property("multidex-enabled").toBoolean() &&
project.android.defaultConfig.minSdkVersion <= 20) {
String flutterMultidexKeepfile = Paths.get(flutterRoot.absolutePath, "packages", "flutter_tools",
"gradle", "flutter_multidex_keepfile.txt")
project.android {
defaultConfig {
multiDexEnabled true
manifestPlaceholders = [applicationName: "io.flutter.app.FlutterMultiDexApplication"]
}
buildTypes {
release {
multiDexKeepFile project.file(flutterMultidexKeepfile)
}
}
}
project.dependencies {
implementation "androidx.multidex:multidex:2.0.1"
}
} else {
String baseApplicationName = "android.app.Application"
if (project.hasProperty("base-application-name")) {
baseApplicationName = project.property("base-application-name")
}
project.android {
defaultConfig {
// Setting to android.app.Application is the same as omitting the attribute.
manifestPlaceholders = [applicationName: baseApplicationName]
}
}
}
if (useLocalEngine()) {
// This is required to pass the local engine to flutter build aot.
String engineOutPath = project.property('local-engine-out')
......
io/flutter/app/FlutterApplication.class
io/flutter/app/FlutterMultiDexApplication.class
io/flutter/embedding/engine/loader/FlutterLoader.class
io/flutter/view/FlutterMain.class
io/flutter/util/PathUtils.class
......@@ -595,8 +595,7 @@ class AndroidDevice extends Device {
androidBuildInfo: AndroidBuildInfo(
debuggingOptions.buildInfo,
targetArchs: <AndroidArch>[androidArch],
fastStart: debuggingOptions.fastStart,
multidexEnabled: platformArgs['multidex'] as bool,
fastStart: debuggingOptions.fastStart
),
);
// Package has been built, so we can get the updated application ID and
......
......@@ -28,7 +28,6 @@ import 'android_builder.dart';
import 'android_studio.dart';
import 'gradle_errors.dart';
import 'gradle_utils.dart';
import 'multidex.dart';
/// The directory where the APK artifact is generated.
Directory getApkDirectory(FlutterProject project) {
......@@ -294,22 +293,6 @@ class AndroidGradleBuilder implements AndroidBuilder {
if (target != null) {
command.add('-Ptarget=$target');
}
// Only attempt adding multidex support if all the flutter generated files exist.
// If the files do not exist and it was unintentional, the app will fail to build
// and prompt the developer if they wish Flutter to add the files again via gradle_error.dart.
if (androidBuildInfo.multidexEnabled &&
multiDexApplicationExists(project.directory) &&
androidManifestHasNameVariable(project.directory)) {
command.add('-Pmultidex-enabled=true');
ensureMultiDexApplicationExists(project.directory);
_logger.printStatus('Building with Flutter multidex support enabled.');
}
// If using v1 embedding, we want to use FlutterApplication as the base app.
final String baseApplicationName =
project.android.getEmbeddingVersion() == AndroidEmbeddingVersion.v2 ?
'android.app.Application' :
'io.flutter.app.FlutterApplication';
command.add('-Pbase-application-name=$baseApplicationName');
final List<DeferredComponent>? deferredComponents = project.manifest.deferredComponents;
if (deferredComponents != null) {
if (deferredComponentsEnabled) {
......@@ -406,7 +389,6 @@ class AndroidGradleBuilder implements AndroidBuilder {
line: detectedGradleErrorLine!,
project: project,
usesAndroidX: usesAndroidX,
multidexEnabled: androidBuildInfo.multidexEnabled,
);
if (retries >= 1) {
......
......@@ -7,12 +7,10 @@ import 'package:meta/meta.dart';
import '../base/error_handling_io.dart';
import '../base/file_system.dart';
import '../base/process.dart';
import '../base/terminal.dart';
import '../globals_null_migrated.dart' as globals;
import '../project.dart';
import '../reporting/reporting.dart';
import 'android_studio.dart';
import 'multidex.dart';
typedef GradleErrorTest = bool Function(String);
......@@ -33,7 +31,6 @@ class GradleHandledError {
required String line,
required FlutterProject project,
required bool usesAndroidX,
required bool multidexEnabled,
}) handler;
/// The [BuildEvent] label is named gradle-[eventLabel].
......@@ -74,104 +71,8 @@ final List<GradleHandledError> gradleErrors = <GradleHandledError>[
minSdkVersion,
transformInputIssue,
lockFileDepMissing,
multidexErrorHandler,
];
// Multidex error message.
@visibleForTesting
final GradleHandledError multidexErrorHandler = GradleHandledError(
test: _lineMatcher(const <String>[
'com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives:',
'The number of method references in a .dex file cannot exceed 64K.',
]),
handler: ({
required String line,
required FlutterProject project,
required bool usesAndroidX,
required bool multidexEnabled,
}) async {
globals.printStatus('${globals.logger.terminal.warningMark} App requires Multidex support', emphasis: true);
if (multidexEnabled) {
globals.printStatus(
'Multidex support is required for your android app to build since the number of methods has exceeded 64k. '
"You may pass the --no-multidex flag to skip Flutter's multidex support to use a manual solution.\n",
indent: 4,
);
if (!androidManifestHasNameVariable(project.directory)) {
globals.printStatus(
r'Your `android/app/src/main/AndroidManifest.xml` does not contain `android:name="${applicationName}"` '
'under the `application` element. This may be due to creating your project with an old version of Flutter. '
'Add the `android:name="\${applicationName}"` attribute to your AndroidManifest.xml to enable Flutter\'s multidex support:\n',
indent: 4,
);
globals.printStatus(r'''
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
<application
...
android:name=''',
indent: 8,
newline: false,
color: TerminalColor.grey,
);
globals.printStatus(r'"${applicationName}"', color: TerminalColor.green, newline: true);
globals.printStatus(r'''
...>
''',
indent: 8,
color: TerminalColor.grey,
);
globals.printStatus(
'You may also roll your own multidex support by following the guide at: https://developer.android.com/studio/build/multidex\n',
indent: 4,
);
return GradleBuildStatus.exit;
}
if (!multiDexApplicationExists(project.directory)) {
globals.printStatus(
'Flutter tool can add multidex support. The following file will be added by flutter:\n',
indent: 4,
);
globals.printStatus(
'android/app/src/main/java/io/flutter/app/FlutterMultiDexApplication.java\n',
indent: 8,
);
String selection = 'n';
// Default to 'no' if no interactive terminal.
try {
selection = await globals.terminal.promptForCharInput(
<String>['y', 'n'],
logger: globals.logger,
prompt: 'Do you want to continue with adding multidex support for Android?',
defaultChoiceIndex: 0,
);
} on StateError catch(e) {
globals.printError(
e.message,
indent: 0,
);
}
if (selection == 'y') {
ensureMultiDexApplicationExists(project.directory);
globals.printStatus(
'Multidex enabled. Retrying build.\n',
indent: 0,
);
return GradleBuildStatus.retry;
}
}
} else {
globals.printStatus(
'Flutter multidex handling is disabled. If you wish to let the tool configure multidex, use the --mutidex flag.',
indent: 4,
);
}
return GradleBuildStatus.exit;
},
eventLabel: 'multidex-error',
);
// Permission defined error message.
@visibleForTesting
final GradleHandledError permissionDeniedErrorHandler = GradleHandledError(
......@@ -182,13 +83,12 @@ final GradleHandledError permissionDeniedErrorHandler = GradleHandledError(
required String line,
required FlutterProject project,
required bool usesAndroidX,
required bool multidexEnabled,
}) async {
globals.printStatus('${globals.logger.terminal.warningMark} Gradle does not have execution permission.', emphasis: true);
globals.printStatus(
'You should change the ownership of the project directory to your user, '
'or move the project to a directory with execute permissions.',
indent: 4,
indent: 4
);
return GradleBuildStatus.exit;
},
......@@ -219,7 +119,6 @@ final GradleHandledError networkErrorHandler = GradleHandledError(
required String line,
required FlutterProject project,
required bool usesAndroidX,
required bool multidexEnabled,
}) async {
globals.printError(
'${globals.logger.terminal.warningMark} Gradle threw an error while downloading artifacts from the network. '
......@@ -249,7 +148,6 @@ final GradleHandledError r8FailureHandler = GradleHandledError(
required String line,
required FlutterProject project,
required bool usesAndroidX,
required bool multidexEnabled,
}) async {
globals.printStatus('${globals.logger.terminal.warningMark} The shrinker may have failed to optimize the Java bytecode.', emphasis: true);
globals.printStatus('To disable the shrinker, pass the `--no-shrink` flag to this command.', indent: 4);
......@@ -271,7 +169,6 @@ final GradleHandledError licenseNotAcceptedHandler = GradleHandledError(
required String line,
required FlutterProject project,
required bool usesAndroidX,
required bool multidexEnabled,
}) async {
const String licenseNotAcceptedMatcher =
r'You have not accepted the license agreements of the following SDK components:\s*\[(.+)\]';
......@@ -305,7 +202,6 @@ final GradleHandledError flavorUndefinedHandler = GradleHandledError(
required String line,
required FlutterProject project,
required bool usesAndroidX,
required bool multidexEnabled,
}) async {
final RunResult tasksRunResult = await globals.processUtils.run(
<String>[
......@@ -378,7 +274,6 @@ final GradleHandledError minSdkVersion = GradleHandledError(
required String line,
required FlutterProject project,
required bool usesAndroidX,
required bool multidexEnabled,
}) async {
final File gradleFile = project.directory
.childDirectory('android')
......@@ -419,7 +314,6 @@ final GradleHandledError transformInputIssue = GradleHandledError(
required String line,
required FlutterProject project,
required bool usesAndroidX,
required bool multidexEnabled,
}) async {
final File gradleFile = project.directory
.childDirectory('android')
......@@ -453,7 +347,6 @@ final GradleHandledError lockFileDepMissing = GradleHandledError(
required String line,
required FlutterProject project,
required bool usesAndroidX,
required bool multidexEnabled,
}) async {
final File gradleFile = project.directory
.childDirectory('android')
......
// 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.
import 'package:xml/xml.dart';
import '../base/file_system.dart';
// These utility methods are used to generate the code for multidex support as
// well as verifying the project is properly set up.
File _getMultiDexApplicationFile(Directory projectDir) {
return projectDir.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('main')
.childDirectory('java')
.childDirectory('io')
.childDirectory('flutter')
.childDirectory('app')
.childFile('FlutterMultiDexApplication.java');
}
/// Creates the FlutterMultiDexApplication.java if it does not exist.
void ensureMultiDexApplicationExists(final Directory projectDir) {
final File applicationFile = _getMultiDexApplicationFile(projectDir);
if (applicationFile.existsSync()) {
return;
}
applicationFile.createSync(recursive: true);
final StringBuffer buffer = StringBuffer();
buffer.write('''
// Generated file.
// If you wish to remove Flutter's multidex support, delete this entire file.
package io.flutter.app;
import android.content.Context;
import androidx.annotation.CallSuper;
import androidx.multidex.MultiDex;
/**
* Extension of {@link io.flutter.app.FlutterApplication}, adding multidex support.
*/
public class FlutterMultiDexApplication extends FlutterApplication {
@Override
@CallSuper
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
''');
applicationFile.writeAsStringSync(buffer.toString(), flush: true);
}
/// Returns true if FlutterMultiDexApplication.java exists.
///
/// This function does not verify the contents of the file.
bool multiDexApplicationExists(final Directory projectDir) {
if (_getMultiDexApplicationFile(projectDir).existsSync()) {
return true;
}
return false;
}
File _getManifestFile(Directory projectDir) {
return projectDir.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('main')
.childFile('AndroidManifest.xml');
}
/// Returns true if the `app` module AndroidManifest.xml includes the
/// <application android:name="${applicationName}"> attribute.
bool androidManifestHasNameVariable(final Directory projectDir) {
final File manifestFile = _getManifestFile(projectDir);
if (!manifestFile.existsSync()) {
return false;
}
XmlDocument document;
try {
document = XmlDocument.parse(manifestFile.readAsStringSync());
} on XmlParserException {
return false;
} on FileSystemException {
return false;
}
// Check for the ${androidName} application attribute.
for (final XmlElement application in document.findAllElements('application')) {
final String? applicationName = application.getAttribute('android:name');
if (applicationName == r'${applicationName}') {
return true;
}
}
return false;
}
......@@ -304,7 +304,6 @@ class AndroidBuildInfo {
],
this.splitPerAbi = false,
this.fastStart = false,
this.multidexEnabled = false,
});
// The build info containing the mode and flavor.
......@@ -322,9 +321,6 @@ class AndroidBuildInfo {
/// Whether to bootstrap an empty application.
final bool fastStart;
/// Whether to enable multidex support for apps with more than 64k methods.
final bool multidexEnabled;
}
/// A summary of the compilation strategy used for Dart.
......
......@@ -35,7 +35,6 @@ class BuildApkCommand extends BuildSubCommand {
addNullSafetyModeOptions(hide: !verboseHelp);
usesAnalyzeSizeFlag();
addAndroidSpecificBuildOptions(hide: !verboseHelp);
addMultidexOption();
argParser
..addFlag('split-per-abi',
negatable: false,
......@@ -100,11 +99,9 @@ class BuildApkCommand extends BuildSubCommand {
buildInfo,
splitPerAbi: boolArg('split-per-abi'),
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
multidexEnabled: boolArg('multidex'),
);
validateBuild(androidBuildInfo);
displayNullSafetyMode(androidBuildInfo.buildInfo);
globals.terminal.usesTerminalUi = true;
await androidBuilder.buildApk(
project: FlutterProject.current(),
target: targetFile,
......
......@@ -39,7 +39,6 @@ class BuildAppBundleCommand extends BuildSubCommand {
addEnableExperimentation(hide: !verboseHelp);
usesAnalyzeSizeFlag();
addAndroidSpecificBuildOptions(hide: !verboseHelp);
addMultidexOption();
argParser.addMultiOption('target-platform',
splitCommas: true,
defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'],
......@@ -111,7 +110,6 @@ class BuildAppBundleCommand extends BuildSubCommand {
final AndroidBuildInfo androidBuildInfo = AndroidBuildInfo(await getBuildInfo(),
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
multidexEnabled: boolArg('multidex'),
);
// Do all setup verification that doesn't involve loading units. Checks that
// require generated loading units are done after gen_snapshot in assemble.
......@@ -146,7 +144,6 @@ class BuildAppBundleCommand extends BuildSubCommand {
validateBuild(androidBuildInfo);
displayNullSafetyMode(androidBuildInfo.buildInfo);
globals.terminal.usesTerminalUi = true;
await androidBuilder.buildAab(
project: FlutterProject.current(),
target: targetFile,
......
......@@ -65,7 +65,6 @@ class DriveCommand extends RunCommandBase {
// to prevent a local network permission dialog on iOS 14+,
// which cannot be accepted or dismissed in a CI environment.
addPublishPort(enabledByDefault: false, verboseHelp: verboseHelp);
addMultidexOption();
argParser
..addFlag('keep-app-running',
defaultsTo: null,
......@@ -252,8 +251,6 @@ class DriveCommand extends RunCommandBase {
'trace-startup': traceStartup,
if (web)
'--no-launch-chrome': true,
if (boolArg('multidex'))
'multidex': true,
}
);
} else {
......
......@@ -249,7 +249,6 @@ class RunCommand extends RunCommandBase {
// This will allow subsequent "flutter attach" commands to connect to the VM
// without needing to know the port.
addPublishPort(verboseHelp: verboseHelp);
addMultidexOption();
argParser
..addFlag('enable-software-rendering',
negatable: false,
......@@ -501,7 +500,6 @@ class RunCommand extends RunCommandBase {
dillOutputPath: stringArg('output-dill'),
stayResident: stayResident,
ipv6: ipv6,
multidexEnabled: boolArg('multidex'),
);
} else if (webMode) {
return webRunnerFactory.createWebRunner(
......
......@@ -416,9 +416,7 @@ class FlutterDevice {
}
devFSWriter = device.createDevFSWriter(package, userIdentifier);
final Map<String, dynamic> platformArgs = <String, dynamic>{
'multidex': hotRunner.multidexEnabled,
};
final Map<String, dynamic> platformArgs = <String, dynamic>{};
await startEchoingDeviceLog();
......
......@@ -93,7 +93,6 @@ class HotRunner extends ResidentRunner {
bool stayResident = true,
bool ipv6 = false,
bool machine = false,
this.multidexEnabled = false,
ResidentDevtoolsHandlerFactory devtoolsHandler = createDefaultHandler,
StopwatchFactory stopwatchFactory = const StopwatchFactory(),
ReloadSourcesHelper reloadSourcesHelper = _defaultReloadSourcesHelper,
......@@ -121,7 +120,6 @@ class HotRunner extends ResidentRunner {
final bool benchmarkMode;
final File applicationBinary;
final bool hostIsIde;
final bool multidexEnabled;
/// When performing a hot restart, the tool needs to upload a new main.dart.dill to
/// each attached device's devfs. Replacing the existing file is not safe and does
......
......@@ -818,16 +818,6 @@ abstract class FlutterCommand extends Command<void> {
);
}
void addMultidexOption({ bool hide = false }) {
argParser.addFlag('multidex',
negatable: true,
defaultsTo: true,
help: 'When enabled, indicates that the app should be built with multidex support. This '
'flag adds the dependencies for multidex when the minimum android sdk is 20 or '
'below. For android sdk versions 21 and above, multidex support is native.',
);
}
/// Adds build options common to all of the desktop build commands.
void addCommonDesktopBuildOptions({ @required bool verboseHelp }) {
addBuildModeFlags(verboseHelp: verboseHelp);
......
......@@ -2,7 +2,6 @@
package="{{androidIdentifier}}">
<application
android:label="{{projectName}}"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
......
......@@ -157,7 +157,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Pbase-application-name=android.app.Application',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=true',
'-Ptree-shake-icons=true',
......@@ -187,7 +186,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Pbase-application-name=android.app.Application',
'-Pdart-obfuscation=false',
'-Psplit-debug-info=${tempDir.path}',
'-Ptrack-widget-creation=true',
......@@ -218,7 +216,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Pbase-application-name=android.app.Application',
'-Pdart-obfuscation=false',
'-Pextra-front-end-options=foo,bar',
'-Ptrack-widget-creation=true',
......@@ -249,7 +246,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Pbase-application-name=android.app.Application',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=true',
'-Ptree-shake-icons=true',
......@@ -285,7 +281,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Pbase-application-name=android.app.Application',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=true',
'-Ptree-shake-icons=true',
......@@ -340,7 +335,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Pbase-application-name=android.app.Application',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=true',
'-Ptree-shake-icons=true',
......@@ -387,7 +381,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Pbase-application-name=android.app.Application',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=true',
'-Ptree-shake-icons=true',
......
......@@ -56,7 +56,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -102,7 +101,6 @@ void main() {
String line,
FlutterProject project,
bool usesAndroidX,
bool multidexEnabled
}) async {
handlerCalled = true;
return GradleBuildStatus.exit;
......@@ -144,7 +142,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -159,7 +156,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -209,7 +205,6 @@ void main() {
String line,
FlutterProject project,
bool usesAndroidX,
bool multidexEnabled
}) async {
return GradleBuildStatus.retry;
},
......@@ -248,7 +243,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -294,7 +288,6 @@ void main() {
String line,
FlutterProject project,
bool usesAndroidX,
bool multidexEnabled
}) async {
handlerCalled = true;
return GradleBuildStatus.exit;
......@@ -336,7 +329,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -396,7 +388,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -411,7 +402,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -460,7 +450,6 @@ void main() {
String line,
FlutterProject project,
bool usesAndroidX,
bool multidexEnabled
}) async {
return GradleBuildStatus.retry;
},
......@@ -499,7 +488,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -592,7 +580,6 @@ void main() {
'-q',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -778,7 +765,6 @@ void main() {
'-Plocal-engine-out=out/android_arm',
'-Ptarget-platform=android-arm',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -852,7 +838,6 @@ void main() {
'-Plocal-engine-out=out/android_arm64',
'-Ptarget-platform=android-arm64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -926,7 +911,6 @@ void main() {
'-Plocal-engine-out=out/android_x86',
'-Ptarget-platform=android-x86',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -1000,7 +984,6 @@ void main() {
'-Plocal-engine-out=out/android_x64',
'-Ptarget-platform=android-x64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......@@ -1073,7 +1056,6 @@ void main() {
'--no-daemon',
'-Ptarget-platform=android-arm,android-arm64,android-x64',
'-Ptarget=lib/main.dart',
'-Pbase-application-name=io.flutter.app.FlutterApplication',
'-Pdart-obfuscation=false',
'-Ptrack-widget-creation=false',
'-Ptree-shake-icons=false',
......
// 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.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/multidex.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/globals_null_migrated.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
void main() {
testUsingContext('ensureMultidexUtilsExists returns when exists', () async {
final Directory directory = globals.fs.currentDirectory;
final File applicationFile = directory.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('main')
.childDirectory('java')
.childDirectory('io')
.childDirectory('flutter')
.childDirectory('app')
.childFile('FlutterMultiDexApplication.java');
applicationFile.createSync(recursive: true);
applicationFile.writeAsStringSync('hello', flush: true);
expect(applicationFile.readAsStringSync(), 'hello');
ensureMultiDexApplicationExists(directory);
// File should remain untouched
expect(applicationFile.readAsStringSync(), 'hello');
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('ensureMultiDexApplicationExists generates when does not exist', () async {
final Directory directory = globals.fs.currentDirectory;
final File applicationFile = directory.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('main')
.childDirectory('java')
.childDirectory('io')
.childDirectory('flutter')
.childDirectory('app')
.childFile('FlutterMultiDexApplication.java');
ensureMultiDexApplicationExists(directory);
final String contents = applicationFile.readAsStringSync();
expect(contents.contains('FlutterMultiDexApplication'), true);
expect(contents.contains('MultiDex.install(this);'), true);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('multiDexApplicationExists false when does not exist', () async {
final Directory directory = globals.fs.currentDirectory;
expect(multiDexApplicationExists(directory), false);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('multiDexApplicationExists true when does exist', () async {
final Directory directory = globals.fs.currentDirectory;
final File utilsFile = directory.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('main')
.childDirectory('java')
.childDirectory('io')
.childDirectory('flutter')
.childDirectory('app')
.childFile('FlutterMultiDexApplication.java');
utilsFile.createSync(recursive: true);
expect(multiDexApplicationExists(directory), true);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('androidManifestHasNameVariable true with valid manifest', () async {
final Directory directory = globals.fs.currentDirectory;
final File applicationFile = directory.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('main')
.childFile('AndroidManifest.xml');
applicationFile.createSync(recursive: true);
applicationFile.writeAsStringSync(r'''
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.multidexapp">
<application
android:label="multidextest2"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
</application>
</manifest>
''', flush: true);
expect(androidManifestHasNameVariable(directory), true);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('androidManifestHasNameVariable false with no android:name attribute', () async {
final Directory directory = globals.fs.currentDirectory;
final File applicationFile = directory.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('main')
.childFile('AndroidManifest.xml');
applicationFile.createSync(recursive: true);
applicationFile.writeAsStringSync(r'''
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.multidexapp">
<application
android:label="multidextest2"
android:icon="@mipmap/ic_launcher">
</application>
''', flush: true);
expect(androidManifestHasNameVariable(directory), false);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('androidManifestHasNameVariable false with incorrect android:name attribute', () async {
final Directory directory = globals.fs.currentDirectory;
final File applicationFile = directory.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('main')
.childFile('AndroidManifest.xml');
applicationFile.createSync(recursive: true);
applicationFile.writeAsStringSync(r'''
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.multidexapp">
<application
android:label="multidextest2"
android:name="io.flutter.app.FlutterApplication"
android:icon="@mipmap/ic_launcher">
</application>
''', flush: true);
expect(androidManifestHasNameVariable(directory), false);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('androidManifestHasNameVariable false with invalid xml manifest', () async {
final Directory directory = globals.fs.currentDirectory;
final File applicationFile = directory.childDirectory('android')
.childDirectory('app')
.childDirectory('src')
.childDirectory('main')
.childFile('AndroidManifest.xml');
applicationFile.createSync(recursive: true);
applicationFile.writeAsStringSync(r'''
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.multidexapp">
<application
android:label="multidextest2"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
</application>
''', flush: true);
expect(androidManifestHasNameVariable(directory), false);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('androidManifestHasNameVariable false with no manifest file', () async {
final Directory directory = globals.fs.currentDirectory;
expect(androidManifestHasNameVariable(directory), false);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});
}
// 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.
// @dart = 2.8
import 'package:file/file.dart';
import 'package:flutter_tools/src/base/io.dart';
import '../src/common.dart';
import 'test_data/multidex_project.dart';
import 'test_driver.dart';
import 'test_utils.dart';
void main() {
Directory tempDir;
FlutterRunTestDriver _flutter;
setUp(() async {
tempDir = createResolvedTempDirectorySync('run_test.');
_flutter = FlutterRunTestDriver(tempDir);
});
tearDown(() async {
await _flutter.stop();
tryToDelete(tempDir);
});
testWithoutContext('simple build apk succeeds', () async {
final MultidexProject project = MultidexProject(true);
await project.setUpIn(tempDir);
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
final ProcessResult result = await processManager.run(<String>[
flutterBin,
...getLocalEngineArguments(),
'build',
'apk',
'--debug',
], workingDirectory: tempDir.path);
expect(result.exitCode, 0);
expect(result.stdout.toString(), contains('app-debug.apk'));
});
testWithoutContext('simple build apk without FlutterMultiDexApplication fails', () async {
final MultidexProject project = MultidexProject(false);
await project.setUpIn(tempDir);
final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter');
final ProcessResult result = await processManager.run(<String>[
flutterBin,
...getLocalEngineArguments(),
'build',
'apk',
'--debug',
], workingDirectory: tempDir.path);
expect(result.stderr.toString(), contains('Cannot fit requested classes in a single dex file'));
expect(result.stderr.toString(), contains('The number of method references in a .dex file cannot exceed 64K.'));
expect(result.exitCode, 1);
});
}
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