Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
1d9edde0
Unverified
Commit
1d9edde0
authored
Oct 14, 2021
by
Gary Qian
Committed by
GitHub
Oct 14, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add multidex flag and automatic multidex support (#90944)
parent
abfcc84e
Changes
21
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1120 additions
and
3 deletions
+1120
-3
flutter.gradle
packages/flutter_tools/gradle/flutter.gradle
+32
-0
flutter_multidex_keepfile.txt
packages/flutter_tools/gradle/flutter_multidex_keepfile.txt
+5
-0
android_device.dart
packages/flutter_tools/lib/src/android/android_device.dart
+2
-1
gradle.dart
packages/flutter_tools/lib/src/android/gradle.dart
+18
-0
gradle_errors.dart
packages/flutter_tools/lib/src/android/gradle_errors.dart
+108
-1
multidex.dart
packages/flutter_tools/lib/src/android/multidex.dart
+99
-0
build_info.dart
packages/flutter_tools/lib/src/build_info.dart
+4
-0
build_apk.dart
packages/flutter_tools/lib/src/commands/build_apk.dart
+3
-0
build_appbundle.dart
packages/flutter_tools/lib/src/commands/build_appbundle.dart
+3
-0
drive.dart
packages/flutter_tools/lib/src/commands/drive.dart
+3
-0
run.dart
packages/flutter_tools/lib/src/commands/run.dart
+2
-0
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+3
-1
run_hot.dart
packages/flutter_tools/lib/src/run_hot.dart
+2
-0
flutter_command.dart
packages/flutter_tools/lib/src/runner/flutter_command.dart
+10
-0
AndroidManifest.xml.tmpl
...shared/android.tmpl/app/src/main/AndroidManifest.xml.tmpl
+1
-0
build_apk_test.dart
...r_tools/test/commands.shard/permeable/build_apk_test.dart
+7
-0
android_gradle_builder_test.dart
...st/general.shard/android/android_gradle_builder_test.dart
+18
-0
gradle_errors_test.dart
..._tools/test/general.shard/android/gradle_errors_test.dart
+228
-0
multidex_test.dart
...utter_tools/test/general.shard/android/multidex_test.dart
+189
-0
multidex_build_test.dart
...ter_tools/test/integration.shard/multidex_build_test.dart
+61
-0
multidex_project.dart
...ls/test/integration.shard/test_data/multidex_project.dart
+322
-0
No files found.
packages/flutter_tools/gradle/flutter.gradle
View file @
1d9edde0
...
@@ -215,6 +215,38 @@ class FlutterPlugin implements Plugin<Project> {
...
@@ -215,6 +215,38 @@ 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
())
{
if
(
useLocalEngine
())
{
// This is required to pass the local engine to flutter build aot.
// This is required to pass the local engine to flutter build aot.
String
engineOutPath
=
project
.
property
(
'local-engine-out'
)
String
engineOutPath
=
project
.
property
(
'local-engine-out'
)
...
...
packages/flutter_tools/gradle/flutter_multidex_keepfile.txt
0 → 100644
View file @
1d9edde0
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
packages/flutter_tools/lib/src/android/android_device.dart
View file @
1d9edde0
...
@@ -595,7 +595,8 @@ class AndroidDevice extends Device {
...
@@ -595,7 +595,8 @@ class AndroidDevice extends Device {
androidBuildInfo:
AndroidBuildInfo
(
androidBuildInfo:
AndroidBuildInfo
(
debuggingOptions
.
buildInfo
,
debuggingOptions
.
buildInfo
,
targetArchs:
<
AndroidArch
>[
androidArch
],
targetArchs:
<
AndroidArch
>[
androidArch
],
fastStart:
debuggingOptions
.
fastStart
fastStart:
debuggingOptions
.
fastStart
,
multidexEnabled:
platformArgs
[
'multidex'
]
as
bool
,
),
),
);
);
// Package has been built, so we can get the updated application ID and
// Package has been built, so we can get the updated application ID and
...
...
packages/flutter_tools/lib/src/android/gradle.dart
View file @
1d9edde0
...
@@ -28,6 +28,7 @@ import 'android_builder.dart';
...
@@ -28,6 +28,7 @@ import 'android_builder.dart';
import
'android_studio.dart'
;
import
'android_studio.dart'
;
import
'gradle_errors.dart'
;
import
'gradle_errors.dart'
;
import
'gradle_utils.dart'
;
import
'gradle_utils.dart'
;
import
'multidex.dart'
;
/// The directory where the APK artifact is generated.
/// The directory where the APK artifact is generated.
Directory
getApkDirectory
(
FlutterProject
project
)
{
Directory
getApkDirectory
(
FlutterProject
project
)
{
...
@@ -293,6 +294,22 @@ class AndroidGradleBuilder implements AndroidBuilder {
...
@@ -293,6 +294,22 @@ class AndroidGradleBuilder implements AndroidBuilder {
if
(
target
!=
null
)
{
if
(
target
!=
null
)
{
command
.
add
(
'-Ptarget=
$target
'
);
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
;
final
List
<
DeferredComponent
>?
deferredComponents
=
project
.
manifest
.
deferredComponents
;
if
(
deferredComponents
!=
null
)
{
if
(
deferredComponents
!=
null
)
{
if
(
deferredComponentsEnabled
)
{
if
(
deferredComponentsEnabled
)
{
...
@@ -389,6 +406,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
...
@@ -389,6 +406,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
line:
detectedGradleErrorLine
!,
line:
detectedGradleErrorLine
!,
project:
project
,
project:
project
,
usesAndroidX:
usesAndroidX
,
usesAndroidX:
usesAndroidX
,
multidexEnabled:
androidBuildInfo
.
multidexEnabled
,
);
);
if
(
retries
>=
1
)
{
if
(
retries
>=
1
)
{
...
...
packages/flutter_tools/lib/src/android/gradle_errors.dart
View file @
1d9edde0
...
@@ -7,10 +7,12 @@ import 'package:meta/meta.dart';
...
@@ -7,10 +7,12 @@ import 'package:meta/meta.dart';
import
'../base/error_handling_io.dart'
;
import
'../base/error_handling_io.dart'
;
import
'../base/file_system.dart'
;
import
'../base/file_system.dart'
;
import
'../base/process.dart'
;
import
'../base/process.dart'
;
import
'../base/terminal.dart'
;
import
'../globals_null_migrated.dart'
as
globals
;
import
'../globals_null_migrated.dart'
as
globals
;
import
'../project.dart'
;
import
'../project.dart'
;
import
'../reporting/reporting.dart'
;
import
'../reporting/reporting.dart'
;
import
'android_studio.dart'
;
import
'android_studio.dart'
;
import
'multidex.dart'
;
typedef
GradleErrorTest
=
bool
Function
(
String
);
typedef
GradleErrorTest
=
bool
Function
(
String
);
...
@@ -31,6 +33,7 @@ class GradleHandledError {
...
@@ -31,6 +33,7 @@ class GradleHandledError {
required
String
line
,
required
String
line
,
required
FlutterProject
project
,
required
FlutterProject
project
,
required
bool
usesAndroidX
,
required
bool
usesAndroidX
,
required
bool
multidexEnabled
,
})
handler
;
})
handler
;
/// The [BuildEvent] label is named gradle-[eventLabel].
/// The [BuildEvent] label is named gradle-[eventLabel].
...
@@ -71,8 +74,104 @@ final List<GradleHandledError> gradleErrors = <GradleHandledError>[
...
@@ -71,8 +74,104 @@ final List<GradleHandledError> gradleErrors = <GradleHandledError>[
minSdkVersion
,
minSdkVersion
,
transformInputIssue
,
transformInputIssue
,
lockFileDepMissing
,
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.
// Permission defined error message.
@visibleForTesting
@visibleForTesting
final
GradleHandledError
permissionDeniedErrorHandler
=
GradleHandledError
(
final
GradleHandledError
permissionDeniedErrorHandler
=
GradleHandledError
(
...
@@ -83,12 +182,13 @@ final GradleHandledError permissionDeniedErrorHandler = GradleHandledError(
...
@@ -83,12 +182,13 @@ final GradleHandledError permissionDeniedErrorHandler = GradleHandledError(
required
String
line
,
required
String
line
,
required
FlutterProject
project
,
required
FlutterProject
project
,
required
bool
usesAndroidX
,
required
bool
usesAndroidX
,
required
bool
multidexEnabled
,
})
async
{
})
async
{
globals
.
printStatus
(
'
${globals.logger.terminal.warningMark}
Gradle does not have execution permission.'
,
emphasis:
true
);
globals
.
printStatus
(
'
${globals.logger.terminal.warningMark}
Gradle does not have execution permission.'
,
emphasis:
true
);
globals
.
printStatus
(
globals
.
printStatus
(
'You should change the ownership of the project directory to your user, '
'You should change the ownership of the project directory to your user, '
'or move the project to a directory with execute permissions.'
,
'or move the project to a directory with execute permissions.'
,
indent:
4
indent:
4
,
);
);
return
GradleBuildStatus
.
exit
;
return
GradleBuildStatus
.
exit
;
},
},
...
@@ -119,6 +219,7 @@ final GradleHandledError networkErrorHandler = GradleHandledError(
...
@@ -119,6 +219,7 @@ final GradleHandledError networkErrorHandler = GradleHandledError(
required
String
line
,
required
String
line
,
required
FlutterProject
project
,
required
FlutterProject
project
,
required
bool
usesAndroidX
,
required
bool
usesAndroidX
,
required
bool
multidexEnabled
,
})
async
{
})
async
{
globals
.
printError
(
globals
.
printError
(
'
${globals.logger.terminal.warningMark}
Gradle threw an error while downloading artifacts from the network. '
'
${globals.logger.terminal.warningMark}
Gradle threw an error while downloading artifacts from the network. '
...
@@ -148,6 +249,7 @@ final GradleHandledError r8FailureHandler = GradleHandledError(
...
@@ -148,6 +249,7 @@ final GradleHandledError r8FailureHandler = GradleHandledError(
required
String
line
,
required
String
line
,
required
FlutterProject
project
,
required
FlutterProject
project
,
required
bool
usesAndroidX
,
required
bool
usesAndroidX
,
required
bool
multidexEnabled
,
})
async
{
})
async
{
globals
.
printStatus
(
'
${globals.logger.terminal.warningMark}
The shrinker may have failed to optimize the Java bytecode.'
,
emphasis:
true
);
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
);
globals
.
printStatus
(
'To disable the shrinker, pass the `--no-shrink` flag to this command.'
,
indent:
4
);
...
@@ -169,6 +271,7 @@ final GradleHandledError licenseNotAcceptedHandler = GradleHandledError(
...
@@ -169,6 +271,7 @@ final GradleHandledError licenseNotAcceptedHandler = GradleHandledError(
required
String
line
,
required
String
line
,
required
FlutterProject
project
,
required
FlutterProject
project
,
required
bool
usesAndroidX
,
required
bool
usesAndroidX
,
required
bool
multidexEnabled
,
})
async
{
})
async
{
const
String
licenseNotAcceptedMatcher
=
const
String
licenseNotAcceptedMatcher
=
r'You have not accepted the license agreements of the following SDK components:\s*\[(.+)\]'
;
r'You have not accepted the license agreements of the following SDK components:\s*\[(.+)\]'
;
...
@@ -202,6 +305,7 @@ final GradleHandledError flavorUndefinedHandler = GradleHandledError(
...
@@ -202,6 +305,7 @@ final GradleHandledError flavorUndefinedHandler = GradleHandledError(
required
String
line
,
required
String
line
,
required
FlutterProject
project
,
required
FlutterProject
project
,
required
bool
usesAndroidX
,
required
bool
usesAndroidX
,
required
bool
multidexEnabled
,
})
async
{
})
async
{
final
RunResult
tasksRunResult
=
await
globals
.
processUtils
.
run
(
final
RunResult
tasksRunResult
=
await
globals
.
processUtils
.
run
(
<
String
>[
<
String
>[
...
@@ -274,6 +378,7 @@ final GradleHandledError minSdkVersion = GradleHandledError(
...
@@ -274,6 +378,7 @@ final GradleHandledError minSdkVersion = GradleHandledError(
required
String
line
,
required
String
line
,
required
FlutterProject
project
,
required
FlutterProject
project
,
required
bool
usesAndroidX
,
required
bool
usesAndroidX
,
required
bool
multidexEnabled
,
})
async
{
})
async
{
final
File
gradleFile
=
project
.
directory
final
File
gradleFile
=
project
.
directory
.
childDirectory
(
'android'
)
.
childDirectory
(
'android'
)
...
@@ -314,6 +419,7 @@ final GradleHandledError transformInputIssue = GradleHandledError(
...
@@ -314,6 +419,7 @@ final GradleHandledError transformInputIssue = GradleHandledError(
required
String
line
,
required
String
line
,
required
FlutterProject
project
,
required
FlutterProject
project
,
required
bool
usesAndroidX
,
required
bool
usesAndroidX
,
required
bool
multidexEnabled
,
})
async
{
})
async
{
final
File
gradleFile
=
project
.
directory
final
File
gradleFile
=
project
.
directory
.
childDirectory
(
'android'
)
.
childDirectory
(
'android'
)
...
@@ -347,6 +453,7 @@ final GradleHandledError lockFileDepMissing = GradleHandledError(
...
@@ -347,6 +453,7 @@ final GradleHandledError lockFileDepMissing = GradleHandledError(
required
String
line
,
required
String
line
,
required
FlutterProject
project
,
required
FlutterProject
project
,
required
bool
usesAndroidX
,
required
bool
usesAndroidX
,
required
bool
multidexEnabled
,
})
async
{
})
async
{
final
File
gradleFile
=
project
.
directory
final
File
gradleFile
=
project
.
directory
.
childDirectory
(
'android'
)
.
childDirectory
(
'android'
)
...
...
packages/flutter_tools/lib/src/android/multidex.dart
0 → 100644
View file @
1d9edde0
// 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;
}
packages/flutter_tools/lib/src/build_info.dart
View file @
1d9edde0
...
@@ -304,6 +304,7 @@ class AndroidBuildInfo {
...
@@ -304,6 +304,7 @@ class AndroidBuildInfo {
],
],
this
.
splitPerAbi
=
false
,
this
.
splitPerAbi
=
false
,
this
.
fastStart
=
false
,
this
.
fastStart
=
false
,
this
.
multidexEnabled
=
false
,
});
});
// The build info containing the mode and flavor.
// The build info containing the mode and flavor.
...
@@ -321,6 +322,9 @@ class AndroidBuildInfo {
...
@@ -321,6 +322,9 @@ class AndroidBuildInfo {
/// Whether to bootstrap an empty application.
/// Whether to bootstrap an empty application.
final
bool
fastStart
;
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.
/// A summary of the compilation strategy used for Dart.
...
...
packages/flutter_tools/lib/src/commands/build_apk.dart
View file @
1d9edde0
...
@@ -35,6 +35,7 @@ class BuildApkCommand extends BuildSubCommand {
...
@@ -35,6 +35,7 @@ class BuildApkCommand extends BuildSubCommand {
addNullSafetyModeOptions
(
hide:
!
verboseHelp
);
addNullSafetyModeOptions
(
hide:
!
verboseHelp
);
usesAnalyzeSizeFlag
();
usesAnalyzeSizeFlag
();
addAndroidSpecificBuildOptions
(
hide:
!
verboseHelp
);
addAndroidSpecificBuildOptions
(
hide:
!
verboseHelp
);
addMultidexOption
();
argParser
argParser
..
addFlag
(
'split-per-abi'
,
..
addFlag
(
'split-per-abi'
,
negatable:
false
,
negatable:
false
,
...
@@ -99,9 +100,11 @@ class BuildApkCommand extends BuildSubCommand {
...
@@ -99,9 +100,11 @@ class BuildApkCommand extends BuildSubCommand {
buildInfo
,
buildInfo
,
splitPerAbi:
boolArg
(
'split-per-abi'
),
splitPerAbi:
boolArg
(
'split-per-abi'
),
targetArchs:
stringsArg
(
'target-platform'
).
map
<
AndroidArch
>(
getAndroidArchForName
),
targetArchs:
stringsArg
(
'target-platform'
).
map
<
AndroidArch
>(
getAndroidArchForName
),
multidexEnabled:
boolArg
(
'multidex'
),
);
);
validateBuild
(
androidBuildInfo
);
validateBuild
(
androidBuildInfo
);
displayNullSafetyMode
(
androidBuildInfo
.
buildInfo
);
displayNullSafetyMode
(
androidBuildInfo
.
buildInfo
);
globals
.
terminal
.
usesTerminalUi
=
true
;
await
androidBuilder
.
buildApk
(
await
androidBuilder
.
buildApk
(
project:
FlutterProject
.
current
(),
project:
FlutterProject
.
current
(),
target:
targetFile
,
target:
targetFile
,
...
...
packages/flutter_tools/lib/src/commands/build_appbundle.dart
View file @
1d9edde0
...
@@ -39,6 +39,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
...
@@ -39,6 +39,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
addEnableExperimentation
(
hide:
!
verboseHelp
);
addEnableExperimentation
(
hide:
!
verboseHelp
);
usesAnalyzeSizeFlag
();
usesAnalyzeSizeFlag
();
addAndroidSpecificBuildOptions
(
hide:
!
verboseHelp
);
addAndroidSpecificBuildOptions
(
hide:
!
verboseHelp
);
addMultidexOption
();
argParser
.
addMultiOption
(
'target-platform'
,
argParser
.
addMultiOption
(
'target-platform'
,
splitCommas:
true
,
splitCommas:
true
,
defaultsTo:
<
String
>[
'android-arm'
,
'android-arm64'
,
'android-x64'
],
defaultsTo:
<
String
>[
'android-arm'
,
'android-arm64'
,
'android-x64'
],
...
@@ -110,6 +111,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
...
@@ -110,6 +111,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
final
AndroidBuildInfo
androidBuildInfo
=
AndroidBuildInfo
(
await
getBuildInfo
(),
final
AndroidBuildInfo
androidBuildInfo
=
AndroidBuildInfo
(
await
getBuildInfo
(),
targetArchs:
stringsArg
(
'target-platform'
).
map
<
AndroidArch
>(
getAndroidArchForName
),
targetArchs:
stringsArg
(
'target-platform'
).
map
<
AndroidArch
>(
getAndroidArchForName
),
multidexEnabled:
boolArg
(
'multidex'
),
);
);
// Do all setup verification that doesn't involve loading units. Checks that
// Do all setup verification that doesn't involve loading units. Checks that
// require generated loading units are done after gen_snapshot in assemble.
// require generated loading units are done after gen_snapshot in assemble.
...
@@ -144,6 +146,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
...
@@ -144,6 +146,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
validateBuild
(
androidBuildInfo
);
validateBuild
(
androidBuildInfo
);
displayNullSafetyMode
(
androidBuildInfo
.
buildInfo
);
displayNullSafetyMode
(
androidBuildInfo
.
buildInfo
);
globals
.
terminal
.
usesTerminalUi
=
true
;
await
androidBuilder
.
buildAab
(
await
androidBuilder
.
buildAab
(
project:
FlutterProject
.
current
(),
project:
FlutterProject
.
current
(),
target:
targetFile
,
target:
targetFile
,
...
...
packages/flutter_tools/lib/src/commands/drive.dart
View file @
1d9edde0
...
@@ -65,6 +65,7 @@ class DriveCommand extends RunCommandBase {
...
@@ -65,6 +65,7 @@ class DriveCommand extends RunCommandBase {
// to prevent a local network permission dialog on iOS 14+,
// to prevent a local network permission dialog on iOS 14+,
// which cannot be accepted or dismissed in a CI environment.
// which cannot be accepted or dismissed in a CI environment.
addPublishPort
(
enabledByDefault:
false
,
verboseHelp:
verboseHelp
);
addPublishPort
(
enabledByDefault:
false
,
verboseHelp:
verboseHelp
);
addMultidexOption
();
argParser
argParser
..
addFlag
(
'keep-app-running'
,
..
addFlag
(
'keep-app-running'
,
defaultsTo:
null
,
defaultsTo:
null
,
...
@@ -251,6 +252,8 @@ class DriveCommand extends RunCommandBase {
...
@@ -251,6 +252,8 @@ class DriveCommand extends RunCommandBase {
'trace-startup'
:
traceStartup
,
'trace-startup'
:
traceStartup
,
if
(
web
)
if
(
web
)
'--no-launch-chrome'
:
true
,
'--no-launch-chrome'
:
true
,
if
(
boolArg
(
'multidex'
))
'multidex'
:
true
,
}
}
);
);
}
else
{
}
else
{
...
...
packages/flutter_tools/lib/src/commands/run.dart
View file @
1d9edde0
...
@@ -249,6 +249,7 @@ class RunCommand extends RunCommandBase {
...
@@ -249,6 +249,7 @@ class RunCommand extends RunCommandBase {
// This will allow subsequent "flutter attach" commands to connect to the VM
// This will allow subsequent "flutter attach" commands to connect to the VM
// without needing to know the port.
// without needing to know the port.
addPublishPort
(
verboseHelp:
verboseHelp
);
addPublishPort
(
verboseHelp:
verboseHelp
);
addMultidexOption
();
argParser
argParser
..
addFlag
(
'enable-software-rendering'
,
..
addFlag
(
'enable-software-rendering'
,
negatable:
false
,
negatable:
false
,
...
@@ -500,6 +501,7 @@ class RunCommand extends RunCommandBase {
...
@@ -500,6 +501,7 @@ class RunCommand extends RunCommandBase {
dillOutputPath:
stringArg
(
'output-dill'
),
dillOutputPath:
stringArg
(
'output-dill'
),
stayResident:
stayResident
,
stayResident:
stayResident
,
ipv6:
ipv6
,
ipv6:
ipv6
,
multidexEnabled:
boolArg
(
'multidex'
),
);
);
}
else
if
(
webMode
)
{
}
else
if
(
webMode
)
{
return
webRunnerFactory
.
createWebRunner
(
return
webRunnerFactory
.
createWebRunner
(
...
...
packages/flutter_tools/lib/src/resident_runner.dart
View file @
1d9edde0
...
@@ -416,7 +416,9 @@ class FlutterDevice {
...
@@ -416,7 +416,9 @@ class FlutterDevice {
}
}
devFSWriter
=
device
.
createDevFSWriter
(
package
,
userIdentifier
);
devFSWriter
=
device
.
createDevFSWriter
(
package
,
userIdentifier
);
final
Map
<
String
,
dynamic
>
platformArgs
=
<
String
,
dynamic
>{};
final
Map
<
String
,
dynamic
>
platformArgs
=
<
String
,
dynamic
>{
'multidex'
:
hotRunner
.
multidexEnabled
,
};
await
startEchoingDeviceLog
();
await
startEchoingDeviceLog
();
...
...
packages/flutter_tools/lib/src/run_hot.dart
View file @
1d9edde0
...
@@ -93,6 +93,7 @@ class HotRunner extends ResidentRunner {
...
@@ -93,6 +93,7 @@ class HotRunner extends ResidentRunner {
bool
stayResident
=
true
,
bool
stayResident
=
true
,
bool
ipv6
=
false
,
bool
ipv6
=
false
,
bool
machine
=
false
,
bool
machine
=
false
,
this
.
multidexEnabled
=
false
,
ResidentDevtoolsHandlerFactory
devtoolsHandler
=
createDefaultHandler
,
ResidentDevtoolsHandlerFactory
devtoolsHandler
=
createDefaultHandler
,
StopwatchFactory
stopwatchFactory
=
const
StopwatchFactory
(),
StopwatchFactory
stopwatchFactory
=
const
StopwatchFactory
(),
ReloadSourcesHelper
reloadSourcesHelper
=
_defaultReloadSourcesHelper
,
ReloadSourcesHelper
reloadSourcesHelper
=
_defaultReloadSourcesHelper
,
...
@@ -120,6 +121,7 @@ class HotRunner extends ResidentRunner {
...
@@ -120,6 +121,7 @@ class HotRunner extends ResidentRunner {
final
bool
benchmarkMode
;
final
bool
benchmarkMode
;
final
File
applicationBinary
;
final
File
applicationBinary
;
final
bool
hostIsIde
;
final
bool
hostIsIde
;
final
bool
multidexEnabled
;
/// When performing a hot restart, the tool needs to upload a new main.dart.dill to
/// 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
/// each attached device's devfs. Replacing the existing file is not safe and does
...
...
packages/flutter_tools/lib/src/runner/flutter_command.dart
View file @
1d9edde0
...
@@ -818,6 +818,16 @@ abstract class FlutterCommand extends Command<void> {
...
@@ -818,6 +818,16 @@ 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.
/// Adds build options common to all of the desktop build commands.
void
addCommonDesktopBuildOptions
({
@required
bool
verboseHelp
})
{
void
addCommonDesktopBuildOptions
({
@required
bool
verboseHelp
})
{
addBuildModeFlags
(
verboseHelp:
verboseHelp
);
addBuildModeFlags
(
verboseHelp:
verboseHelp
);
...
...
packages/flutter_tools/templates/app_shared/android.tmpl/app/src/main/AndroidManifest.xml.tmpl
View file @
1d9edde0
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
package="{{androidIdentifier}}">
package="{{androidIdentifier}}">
<application
<application
android:label="{{projectName}}"
android:label="{{projectName}}"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/ic_launcher">
<activity
<activity
android:name=".MainActivity"
android:name=".MainActivity"
...
...
packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart
View file @
1d9edde0
...
@@ -157,6 +157,7 @@ void main() {
...
@@ -157,6 +157,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Pbase-application-name=android.app.Application'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=true'
,
'-Ptrack-widget-creation=true'
,
'-Ptree-shake-icons=true'
,
'-Ptree-shake-icons=true'
,
...
@@ -186,6 +187,7 @@ void main() {
...
@@ -186,6 +187,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Pbase-application-name=android.app.Application'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Psplit-debug-info=
${tempDir.path}
'
,
'-Psplit-debug-info=
${tempDir.path}
'
,
'-Ptrack-widget-creation=true'
,
'-Ptrack-widget-creation=true'
,
...
@@ -216,6 +218,7 @@ void main() {
...
@@ -216,6 +218,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Pbase-application-name=android.app.Application'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Pextra-front-end-options=foo,bar'
,
'-Pextra-front-end-options=foo,bar'
,
'-Ptrack-widget-creation=true'
,
'-Ptrack-widget-creation=true'
,
...
@@ -246,6 +249,7 @@ void main() {
...
@@ -246,6 +249,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Pbase-application-name=android.app.Application'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=true'
,
'-Ptrack-widget-creation=true'
,
'-Ptree-shake-icons=true'
,
'-Ptree-shake-icons=true'
,
...
@@ -281,6 +285,7 @@ void main() {
...
@@ -281,6 +285,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Pbase-application-name=android.app.Application'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=true'
,
'-Ptrack-widget-creation=true'
,
'-Ptree-shake-icons=true'
,
'-Ptree-shake-icons=true'
,
...
@@ -335,6 +340,7 @@ void main() {
...
@@ -335,6 +340,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Pbase-application-name=android.app.Application'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=true'
,
'-Ptrack-widget-creation=true'
,
'-Ptree-shake-icons=true'
,
'-Ptree-shake-icons=true'
,
...
@@ -381,6 +387,7 @@ void main() {
...
@@ -381,6 +387,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptarget=
${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Pbase-application-name=android.app.Application'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=true'
,
'-Ptrack-widget-creation=true'
,
'-Ptree-shake-icons=true'
,
'-Ptree-shake-icons=true'
,
...
...
packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart
View file @
1d9edde0
...
@@ -56,6 +56,7 @@ void main() {
...
@@ -56,6 +56,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -101,6 +102,7 @@ void main() {
...
@@ -101,6 +102,7 @@ void main() {
String
line
,
String
line
,
FlutterProject
project
,
FlutterProject
project
,
bool
usesAndroidX
,
bool
usesAndroidX
,
bool
multidexEnabled
})
async
{
})
async
{
handlerCalled
=
true
;
handlerCalled
=
true
;
return
GradleBuildStatus
.
exit
;
return
GradleBuildStatus
.
exit
;
...
@@ -142,6 +144,7 @@ void main() {
...
@@ -142,6 +144,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -156,6 +159,7 @@ void main() {
...
@@ -156,6 +159,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -205,6 +209,7 @@ void main() {
...
@@ -205,6 +209,7 @@ void main() {
String
line
,
String
line
,
FlutterProject
project
,
FlutterProject
project
,
bool
usesAndroidX
,
bool
usesAndroidX
,
bool
multidexEnabled
})
async
{
})
async
{
return
GradleBuildStatus
.
retry
;
return
GradleBuildStatus
.
retry
;
},
},
...
@@ -243,6 +248,7 @@ void main() {
...
@@ -243,6 +248,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -288,6 +294,7 @@ void main() {
...
@@ -288,6 +294,7 @@ void main() {
String
line
,
String
line
,
FlutterProject
project
,
FlutterProject
project
,
bool
usesAndroidX
,
bool
usesAndroidX
,
bool
multidexEnabled
})
async
{
})
async
{
handlerCalled
=
true
;
handlerCalled
=
true
;
return
GradleBuildStatus
.
exit
;
return
GradleBuildStatus
.
exit
;
...
@@ -329,6 +336,7 @@ void main() {
...
@@ -329,6 +336,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -388,6 +396,7 @@ void main() {
...
@@ -388,6 +396,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -402,6 +411,7 @@ void main() {
...
@@ -402,6 +411,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -450,6 +460,7 @@ void main() {
...
@@ -450,6 +460,7 @@ void main() {
String
line
,
String
line
,
FlutterProject
project
,
FlutterProject
project
,
bool
usesAndroidX
,
bool
usesAndroidX
,
bool
multidexEnabled
})
async
{
})
async
{
return
GradleBuildStatus
.
retry
;
return
GradleBuildStatus
.
retry
;
},
},
...
@@ -488,6 +499,7 @@ void main() {
...
@@ -488,6 +499,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm64'
,
'-Ptarget-platform=android-arm64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -580,6 +592,7 @@ void main() {
...
@@ -580,6 +592,7 @@ void main() {
'-q'
,
'-q'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -765,6 +778,7 @@ void main() {
...
@@ -765,6 +778,7 @@ void main() {
'-Plocal-engine-out=out/android_arm'
,
'-Plocal-engine-out=out/android_arm'
,
'-Ptarget-platform=android-arm'
,
'-Ptarget-platform=android-arm'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -838,6 +852,7 @@ void main() {
...
@@ -838,6 +852,7 @@ void main() {
'-Plocal-engine-out=out/android_arm64'
,
'-Plocal-engine-out=out/android_arm64'
,
'-Ptarget-platform=android-arm64'
,
'-Ptarget-platform=android-arm64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -911,6 +926,7 @@ void main() {
...
@@ -911,6 +926,7 @@ void main() {
'-Plocal-engine-out=out/android_x86'
,
'-Plocal-engine-out=out/android_x86'
,
'-Ptarget-platform=android-x86'
,
'-Ptarget-platform=android-x86'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -984,6 +1000,7 @@ void main() {
...
@@ -984,6 +1000,7 @@ void main() {
'-Plocal-engine-out=out/android_x64'
,
'-Plocal-engine-out=out/android_x64'
,
'-Ptarget-platform=android-x64'
,
'-Ptarget-platform=android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
@@ -1056,6 +1073,7 @@ void main() {
...
@@ -1056,6 +1073,7 @@ void main() {
'--no-daemon'
,
'--no-daemon'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget-platform=android-arm,android-arm64,android-x64'
,
'-Ptarget=lib/main.dart'
,
'-Ptarget=lib/main.dart'
,
'-Pbase-application-name=io.flutter.app.FlutterApplication'
,
'-Pdart-obfuscation=false'
,
'-Pdart-obfuscation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptrack-widget-creation=false'
,
'-Ptree-shake-icons=false'
,
'-Ptree-shake-icons=false'
,
...
...
packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart
View file @
1d9edde0
This diff is collapsed.
Click to expand it.
packages/flutter_tools/test/general.shard/android/multidex_test.dart
0 → 100644
View file @
1d9edde0
// 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
(),
});
}
packages/flutter_tools/test/integration.shard/multidex_build_test.dart
0 → 100644
View file @
1d9edde0
// 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
);
});
}
packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart
0 → 100644
View file @
1d9edde0
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment