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
f098de1f
Unverified
Commit
f098de1f
authored
Sep 11, 2019
by
Emmanuel Garcia
Committed by
GitHub
Sep 11, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enable Proguard by default on release mode (#39986)
parent
362cde43
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
586 additions
and
122 deletions
+586
-122
flutter.gradle
packages/flutter_tools/gradle/flutter.gradle
+32
-10
flutter_proguard_rules.pro
packages/flutter_tools/gradle/flutter_proguard_rules.pro
+11
-0
gradle.dart
packages/flutter_tools/lib/src/android/gradle.dart
+68
-42
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
+9
-2
build_appbundle.dart
packages/flutter_tools/lib/src/commands/build_appbundle.dart
+8
-1
context_runner.dart
packages/flutter_tools/lib/src/context_runner.dart
+2
-0
channel_test.dart
packages/flutter_tools/test/general.shard/channel_test.dart
+1
-16
build_apk_test.dart
...ter_tools/test/general.shard/commands/build_apk_test.dart
+213
-18
build_appbundle_test.dart
...ols/test/general.shard/commands/build_appbundle_test.dart
+217
-16
upgrade_test.dart
...utter_tools/test/general.shard/commands/upgrade_test.dart
+1
-17
common.dart
packages/flutter_tools/test/src/common.dart
+2
-0
mocks.dart
packages/flutter_tools/test/src/mocks.dart
+18
-0
No files found.
packages/flutter_tools/gradle/flutter.gradle
View file @
f098de1f
...
...
@@ -132,16 +132,6 @@ class FlutterPlugin implements Plugin<Project> {
}
}
// Add custom build types
project
.
android
.
buildTypes
{
profile
{
initWith
debug
if
(
it
.
hasProperty
(
'matchingFallbacks'
))
{
matchingFallbacks
=
[
'debug'
,
'release'
]
}
}
}
String
flutterRootPath
=
resolveProperty
(
project
,
"flutter.sdk"
,
System
.
env
.
FLUTTER_ROOT
)
if
(
flutterRootPath
==
null
)
{
throw
new
GradleException
(
"Flutter SDK not found. Define location with flutter.sdk in the local.properties file or with a FLUTTER_ROOT environment variable."
)
...
...
@@ -154,6 +144,30 @@ class FlutterPlugin implements Plugin<Project> {
String
flutterExecutableName
=
Os
.
isFamily
(
Os
.
FAMILY_WINDOWS
)
?
"flutter.bat"
:
"flutter"
flutterExecutable
=
Paths
.
get
(
flutterRoot
.
absolutePath
,
"bin"
,
flutterExecutableName
).
toFile
();
// Add custom build types.
project
.
android
.
buildTypes
{
profile
{
initWith
debug
if
(
it
.
hasProperty
(
"matchingFallbacks"
))
{
matchingFallbacks
=
[
"debug"
,
"release"
]
}
}
}
if
(
useProguard
(
project
))
{
String
flutterProguardRules
=
Paths
.
get
(
flutterRoot
.
absolutePath
,
"packages"
,
"flutter_tools"
,
"gradle"
,
"flutter_proguard_rules.pro"
)
project
.
android
.
buildTypes
{
release
{
minifyEnabled
true
useProguard
true
// Fallback to `android/app/proguard-rules.pro`.
// This way, custom Proguard rules can be configured as needed.
proguardFiles
project
.
android
.
getDefaultProguardFile
(
"proguard-android.txt"
),
flutterProguardRules
,
"proguard-rules.pro"
}
}
}
if
(
useLocalEngine
(
project
))
{
String
engineOutPath
=
project
.
property
(
'localEngineOut'
)
File
engineOut
=
project
.
file
(
engineOutPath
)
...
...
@@ -375,6 +389,14 @@ class FlutterPlugin implements Plugin<Project> {
return
false
}
private
static
Boolean
useProguard
(
Project
project
)
{
if
(
project
.
hasProperty
(
'proguard'
))
{
return
project
.
property
(
'proguard'
).
toBoolean
()
}
return
false
}
private
static
Boolean
buildPluginAsAar
()
{
return
System
.
getProperty
(
'build-plugins-as-aars'
)
==
'true'
}
...
...
packages/flutter_tools/gradle/flutter_proguard_rules.pro
0 → 100644
View file @
f098de1f
# Prevents `Fragment and FragmentActivity not found`.
# TODO(blasten): Remove once we bring the Maven dependencies.
-
dontwarn
io
.
flutter
.
embedding
.
**
# Build the ephemeral app in a module project.
# Prevents: Warning: library class <plugin-package> depends on program class io.flutter.plugin.**
# This is due to plugins (libraries) depending on the embedding (the program jar)
-
dontwarn
io
.
flutter
.
plugin
.
**
# The android.** package is provided by the OS at runtime.
-
dontwarn
android
.
**
packages/flutter_tools/lib/src/android/gradle.dart
View file @
f098de1f
...
...
@@ -10,6 +10,7 @@ import 'package:meta/meta.dart';
import
'../android/android_sdk.dart'
;
import
'../artifacts.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/logger.dart'
;
import
'../base/os.dart'
;
...
...
@@ -28,11 +29,39 @@ import '../reporting/reporting.dart';
import
'android_sdk.dart'
;
import
'android_studio.dart'
;
final
RegExp
_assembleTaskPattern
=
RegExp
(
r'assemble(\S+)'
);
/// Gradle utils in the current [AppContext].
GradleUtils
get
gradleUtils
=>
context
.
get
<
GradleUtils
>();
/// Provides utilities to run a Gradle task,
/// such as finding the Gradle executable or constructing a Gradle project.
class
GradleUtils
{
/// Empty constructor.
GradleUtils
();
String
_cachedExecutable
;
/// Gets the Gradle executable path.
/// This is the `gradlew` or `gradlew.bat` script in the `android/` directory.
Future
<
String
>
getExecutable
(
FlutterProject
project
)
async
{
_cachedExecutable
??=
await
_initializeGradle
(
project
);
return
_cachedExecutable
;
}
GradleProject
_cachedAppProject
;
/// Gets the [GradleProject] for the current [FlutterProject] if built as an app.
Future
<
GradleProject
>
get
appProject
async
{
_cachedAppProject
??=
await
_readGradleProject
(
isLibrary:
false
);
return
_cachedAppProject
;
}
GradleProject
_cachedGradleAppProject
;
GradleProject
_cachedGradleLibraryProject
;
String
_cachedGradleExecutable
;
GradleProject
_cachedLibraryProject
;
/// Gets the [GradleProject] for the current [FlutterProject] if built as a library.
Future
<
GradleProject
>
get
libraryProject
async
{
_cachedLibraryProject
??=
await
_readGradleProject
(
isLibrary:
true
);
return
_cachedLibraryProject
;
}
}
final
RegExp
_assembleTaskPattern
=
RegExp
(
r'assemble(\S+)'
);
enum
FlutterPluginVersion
{
none
,
...
...
@@ -103,29 +132,20 @@ Future<File> getGradleAppOut(AndroidProject androidProject) async {
case
FlutterPluginVersion
.
managed
:
// Fall through. The managed plugin matches plugin v2 for now.
case
FlutterPluginVersion
.
v2
:
return
fs
.
file
((
await
_gradleAppProject
()).
apkDirectory
.
childFile
(
'app.apk'
));
final
GradleProject
gradleProject
=
await
gradleUtils
.
appProject
;
return
fs
.
file
(
gradleProject
.
apkDirectory
.
childFile
(
'app.apk'
));
}
return
null
;
}
Future
<
GradleProject
>
_gradleAppProject
()
async
{
_cachedGradleAppProject
??=
await
_readGradleProject
(
isLibrary:
false
);
return
_cachedGradleAppProject
;
}
Future
<
GradleProject
>
_gradleLibraryProject
()
async
{
_cachedGradleLibraryProject
??=
await
_readGradleProject
(
isLibrary:
true
);
return
_cachedGradleLibraryProject
;
}
/// Runs `gradlew dependencies`, ensuring that dependencies are resolved and
/// potentially downloaded.
Future
<
void
>
checkGradleDependencies
()
async
{
final
Status
progress
=
logger
.
startProgress
(
'Ensuring gradle dependencies are up to date...'
,
timeout:
timeoutConfiguration
.
slowOperation
);
final
FlutterProject
flutterProject
=
FlutterProject
.
current
();
final
String
gradle
=
await
_ensureGrad
le
(
flutterProject
);
final
String
gradle
w
=
await
gradleUtils
.
getExecutab
le
(
flutterProject
);
await
runCheckedAsync
(
<
String
>[
gradle
,
'dependencies'
],
<
String
>[
gradle
w
,
'dependencies'
],
workingDirectory:
flutterProject
.
android
.
hostAppGradleRoot
.
path
,
environment:
_gradleEnv
,
);
...
...
@@ -189,7 +209,8 @@ void createSettingsAarGradle(Directory androidDirectory) {
// of calculating the app properties using Gradle. This may take minutes.
Future
<
GradleProject
>
_readGradleProject
({
bool
isLibrary
=
false
})
async
{
final
FlutterProject
flutterProject
=
FlutterProject
.
current
();
final
String
gradle
=
await
_ensureGradle
(
flutterProject
);
final
String
gradlew
=
await
gradleUtils
.
getExecutable
(
flutterProject
);
updateLocalProperties
(
project:
flutterProject
);
final
FlutterManifest
manifest
=
flutterProject
.
manifest
;
...
...
@@ -213,12 +234,12 @@ Future<GradleProject> _readGradleProject({bool isLibrary = false}) async {
// flavors and build types defined in the project. If gradle fails, then check if the failure is due to t
try
{
final
RunResult
propertiesRunResult
=
await
runCheckedAsync
(
<
String
>[
gradle
,
isLibrary
?
'properties'
:
'app:properties'
],
<
String
>[
gradle
w
,
isLibrary
?
'properties'
:
'app:properties'
],
workingDirectory:
hostAppGradleRoot
.
path
,
environment:
_gradleEnv
,
);
final
RunResult
tasksRunResult
=
await
runCheckedAsync
(
<
String
>[
gradle
,
isLibrary
?
'tasks'
:
'app:tasks'
,
'--all'
,
'--console=auto'
],
<
String
>[
gradle
w
,
isLibrary
?
'tasks'
:
'app:tasks'
,
'--all'
,
'--console=auto'
],
workingDirectory:
hostAppGradleRoot
.
path
,
environment:
_gradleEnv
,
);
...
...
@@ -274,11 +295,6 @@ String _locateGradlewExecutable(Directory directory) {
return
null
;
}
Future
<
String
>
_ensureGradle
(
FlutterProject
project
)
async
{
_cachedGradleExecutable
??=
await
_initializeGradle
(
project
);
return
_cachedGradleExecutable
;
}
// Note: Gradle may be bootstrapped and possibly downloaded as a side-effect
// of validating the Gradle executable. This may take several seconds.
Future
<
String
>
_initializeGradle
(
FlutterProject
project
)
async
{
...
...
@@ -492,17 +508,15 @@ Future<void> buildGradleProject({
// from the local.properties file.
updateLocalProperties
(
project:
project
,
buildInfo:
androidBuildInfo
.
buildInfo
);
final
String
gradle
=
await
_ensureGradle
(
project
);
switch
(
getFlutterPluginVersion
(
project
.
android
))
{
case
FlutterPluginVersion
.
none
:
// Fall through. Pretend it's v1, and just go for it.
case
FlutterPluginVersion
.
v1
:
return
_buildGradleProjectV1
(
project
,
gradle
);
return
_buildGradleProjectV1
(
project
);
case
FlutterPluginVersion
.
managed
:
// Fall through. Managed plugin builds the same way as plugin v2.
case
FlutterPluginVersion
.
v2
:
return
_buildGradleProjectV2
(
project
,
gradle
,
androidBuildInfo
,
target
,
isBuildingBundle
);
return
_buildGradleProjectV2
(
project
,
androidBuildInfo
,
target
,
isBuildingBundle
);
}
}
...
...
@@ -516,9 +530,9 @@ Future<void> buildGradleAar({
GradleProject
gradleProject
;
if
(
manifest
.
isModule
)
{
gradleProject
=
await
_gradleAppProject
()
;
gradleProject
=
await
gradleUtils
.
appProject
;
}
else
if
(
manifest
.
isPlugin
)
{
gradleProject
=
await
_gradleLibraryProject
()
;
gradleProject
=
await
gradleUtils
.
libraryProject
;
}
else
{
throwToolExit
(
'AARs can only be built for plugin or module projects.'
);
}
...
...
@@ -538,12 +552,11 @@ Future<void> buildGradleAar({
multilineOutput:
true
,
);
final
String
gradle
=
await
_ensureGradle
(
project
);
final
String
gradlePath
=
fs
.
file
(
gradle
).
absolute
.
path
;
final
String
gradlew
=
await
gradleUtils
.
getExecutable
(
project
);
final
String
flutterRoot
=
fs
.
path
.
absolute
(
Cache
.
flutterRoot
);
final
String
initScript
=
fs
.
path
.
join
(
flutterRoot
,
'packages'
,
'flutter_tools'
,
'gradle'
,
'aar_init_script.gradle'
);
final
List
<
String
>
command
=
<
String
>[
gradle
Path
,
gradle
w
,
'-I=
$initScript
'
,
'-Pflutter-root=
$flutterRoot
'
,
'-Poutput-dir=
${gradleProject.buildDirectory}
'
,
...
...
@@ -601,7 +614,8 @@ Future<void> buildGradleAar({
printStatus
(
'Built
${fs.path.relative(repoDirectory.path)}
.'
,
color:
TerminalColor
.
green
);
}
Future
<
void
>
_buildGradleProjectV1
(
FlutterProject
project
,
String
gradle
)
async
{
Future
<
void
>
_buildGradleProjectV1
(
FlutterProject
project
)
async
{
final
String
gradlew
=
await
gradleUtils
.
getExecutable
(
project
);
// Run 'gradlew build'.
final
Status
status
=
logger
.
startProgress
(
'Running
\'
gradlew build
\'
...'
,
...
...
@@ -610,7 +624,7 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async
);
final
Stopwatch
sw
=
Stopwatch
()..
start
();
final
int
exitCode
=
await
runCommandAndStreamOutput
(
<
String
>[
fs
.
file
(
gradle
).
absolute
.
path
,
'build'
],
<
String
>[
fs
.
file
(
gradle
w
).
absolute
.
path
,
'build'
],
workingDirectory:
project
.
android
.
hostAppGradleRoot
.
path
,
allowReentrantFlutter:
true
,
environment:
_gradleEnv
,
...
...
@@ -661,12 +675,12 @@ void printUndefinedTask(GradleProject project, BuildInfo buildInfo) {
Future
<
void
>
_buildGradleProjectV2
(
FlutterProject
flutterProject
,
String
gradle
,
AndroidBuildInfo
androidBuildInfo
,
String
target
,
bool
isBuildingBundle
,
)
async
{
final
GradleProject
project
=
await
_gradleAppProject
();
final
String
gradlew
=
await
gradleUtils
.
getExecutable
(
flutterProject
);
final
GradleProject
project
=
await
gradleUtils
.
appProject
;
final
BuildInfo
buildInfo
=
androidBuildInfo
.
buildInfo
;
String
assembleTask
;
...
...
@@ -685,8 +699,7 @@ Future<void> _buildGradleProjectV2(
timeout:
timeoutConfiguration
.
slowOperation
,
multilineOutput:
true
,
);
final
String
gradlePath
=
fs
.
file
(
gradle
).
absolute
.
path
;
final
List
<
String
>
command
=
<
String
>[
gradlePath
];
final
List
<
String
>
command
=
<
String
>[
gradlew
];
if
(
logger
.
isVerbose
)
{
command
.
add
(
'-Pverbose=true'
);
}
else
{
...
...
@@ -712,6 +725,8 @@ Future<void> _buildGradleProjectV2(
command
.
add
(
'-Pfilesystem-scheme=
${buildInfo.fileSystemScheme}
'
);
if
(
androidBuildInfo
.
splitPerAbi
)
command
.
add
(
'-Psplit-per-abi=true'
);
if
(
androidBuildInfo
.
proguard
)
command
.
add
(
'-Pproguard=true'
);
if
(
androidBuildInfo
.
targetArchs
.
isNotEmpty
)
{
final
String
targetPlatforms
=
androidBuildInfo
.
targetArchs
.
map
(
getPlatformNameForAndroidArch
).
join
(
','
);
...
...
@@ -727,6 +742,7 @@ Future<void> _buildGradleProjectV2(
}
command
.
add
(
assembleTask
);
bool
potentialAndroidXFailure
=
false
;
bool
potentialProguardFailure
=
false
;
final
Stopwatch
sw
=
Stopwatch
()..
start
();
int
exitCode
=
1
;
try
{
...
...
@@ -743,13 +759,17 @@ Future<void> _buildGradleProjectV2(
if
(!
isAndroidXPluginWarning
&&
androidXFailureRegex
.
hasMatch
(
line
))
{
potentialAndroidXFailure
=
true
;
}
// Proguard errors include this url.
if
(!
potentialProguardFailure
&&
androidBuildInfo
.
proguard
&&
line
.
contains
(
'http://proguard.sourceforge.net'
))
{
potentialProguardFailure
=
true
;
}
// Always print the full line in verbose mode.
if
(
logger
.
isVerbose
)
{
return
line
;
}
else
if
(
isAndroidXPluginWarning
||
!
ndkMessageFilter
.
hasMatch
(
line
))
{
return
null
;
}
return
line
;
},
);
...
...
@@ -758,7 +778,13 @@ Future<void> _buildGradleProjectV2(
}
if
(
exitCode
!=
0
)
{
if
(
potentialAndroidXFailure
)
{
if
(
potentialProguardFailure
)
{
final
String
exclamationMark
=
terminal
.
color
(
'[!]'
,
TerminalColor
.
red
);
printStatus
(
'
$exclamationMark
Proguard may have failed to optimize the Java bytecode.'
,
emphasis:
true
);
printStatus
(
'To disable proguard, pass the `--no-proguard` flag to this command.'
,
indent:
4
);
printStatus
(
'To learn more about Proguard, see: https://flutter.dev/docs/deployment/android#enabling-proguard'
,
indent:
4
);
BuildEvent
(
'proguard-failure'
).
send
();
}
else
if
(
potentialAndroidXFailure
)
{
printStatus
(
'AndroidX incompatibilities may have caused this build to fail. See https://goo.gl/CP92wY.'
);
BuildEvent
(
'android-x-failure'
).
send
();
}
...
...
packages/flutter_tools/lib/src/build_info.dart
View file @
f098de1f
...
...
@@ -92,6 +92,7 @@ class AndroidBuildInfo {
AndroidArch
.
arm64_v8a
,
],
this
.
splitPerAbi
=
false
,
this
.
proguard
=
false
,
});
// The build info containing the mode and flavor.
...
...
@@ -104,6 +105,9 @@ class AndroidBuildInfo {
/// will be produced.
final
bool
splitPerAbi
;
/// Whether to enable Proguard on release mode.
final
bool
proguard
;
/// The target platforms for the build.
final
Iterable
<
AndroidArch
>
targetArchs
;
}
...
...
packages/flutter_tools/lib/src/commands/build_apk.dart
View file @
f098de1f
...
...
@@ -25,9 +25,15 @@ class BuildApkCommand extends BuildSubCommand {
argParser
..
addFlag
(
'split-per-abi'
,
negatable:
false
,
help:
'Whether to split the APKs per ABIs.'
help:
'Whether to split the APKs per ABIs.
'
'To learn more, see: https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split'
,
)
..
addFlag
(
'proguard'
,
negatable:
true
,
defaultsTo:
true
,
help:
'Whether to enable Proguard on release mode. '
'To learn more, see: https://flutter.dev/docs/deployment/android#enabling-proguard'
,
)
..
addMultiOption
(
'target-platform'
,
splitCommas:
true
,
defaultsTo:
<
String
>[
'android-arm'
,
'android-arm64'
],
...
...
@@ -79,7 +85,8 @@ class BuildApkCommand extends BuildSubCommand {
final
BuildInfo
buildInfo
=
getBuildInfo
();
final
AndroidBuildInfo
androidBuildInfo
=
AndroidBuildInfo
(
buildInfo
,
splitPerAbi:
argResults
[
'split-per-abi'
],
targetArchs:
argResults
[
'target-platform'
].
map
<
AndroidArch
>(
getAndroidArchForName
)
targetArchs:
argResults
[
'target-platform'
].
map
<
AndroidArch
>(
getAndroidArchForName
),
proguard:
argResults
[
'proguard'
],
);
if
(
buildInfo
.
isRelease
&&
!
androidBuildInfo
.
splitPerAbi
&&
androidBuildInfo
.
targetArchs
.
length
>
1
)
{
...
...
packages/flutter_tools/lib/src/commands/build_appbundle.dart
View file @
f098de1f
...
...
@@ -22,6 +22,12 @@ class BuildAppBundleCommand extends BuildSubCommand {
argParser
..
addFlag
(
'track-widget-creation'
,
negatable:
false
,
hide:
!
verboseHelp
)
..
addFlag
(
'proguard'
,
negatable:
true
,
defaultsTo:
true
,
help:
'Whether to enable Proguard on release mode. '
'To learn more, see: https://flutter.dev/docs/deployment/android#enabling-proguard'
,
)
..
addMultiOption
(
'target-platform'
,
splitCommas:
true
,
defaultsTo:
<
String
>[
'android-arm'
,
'android-arm64'
],
...
...
@@ -63,7 +69,8 @@ class BuildAppBundleCommand extends BuildSubCommand {
@override
Future
<
FlutterCommandResult
>
runCommand
()
async
{
final
AndroidBuildInfo
androidBuildInfo
=
AndroidBuildInfo
(
getBuildInfo
(),
targetArchs:
argResults
[
'target-platform'
].
map
<
AndroidArch
>(
getAndroidArchForName
)
targetArchs:
argResults
[
'target-platform'
].
map
<
AndroidArch
>(
getAndroidArchForName
),
proguard:
argResults
[
'proguard'
],
);
await
androidBuilder
.
buildAab
(
project:
FlutterProject
.
current
(),
...
...
packages/flutter_tools/lib/src/context_runner.dart
View file @
f098de1f
...
...
@@ -7,6 +7,7 @@ import 'dart:async';
import
'android/android_sdk.dart'
;
import
'android/android_studio.dart'
;
import
'android/android_workflow.dart'
;
import
'android/gradle.dart'
;
import
'application_package.dart'
;
import
'artifacts.dart'
;
import
'asset.dart'
;
...
...
@@ -89,6 +90,7 @@ Future<T> runInContext<T>(
FuchsiaSdk:
()
=>
FuchsiaSdk
(),
FuchsiaWorkflow:
()
=>
FuchsiaWorkflow
(),
GenSnapshot:
()
=>
const
GenSnapshot
(),
GradleUtils:
()
=>
GradleUtils
(),
HotRunnerConfig:
()
=>
HotRunnerConfig
(),
IMobileDevice:
()
=>
IMobileDevice
(),
IOSDeploy:
()
=>
const
IOSDeploy
(),
...
...
packages/flutter_tools/test/general.shard/channel_test.dart
View file @
f098de1f
...
...
@@ -3,7 +3,6 @@
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
hide
File
;
import
'package:args/command_runner.dart'
;
...
...
@@ -17,21 +16,7 @@ import 'package:process/process.dart';
import
'../src/common.dart'
;
import
'../src/context.dart'
;
Process
createMockProcess
(
{
int
exitCode
=
0
,
String
stdout
=
''
,
String
stderr
=
''
})
{
final
Stream
<
List
<
int
>>
stdoutStream
=
Stream
<
List
<
int
>>.
fromIterable
(<
List
<
int
>>[
utf8
.
encode
(
stdout
),
]);
final
Stream
<
List
<
int
>>
stderrStream
=
Stream
<
List
<
int
>>.
fromIterable
(<
List
<
int
>>[
utf8
.
encode
(
stderr
),
]);
final
Process
process
=
MockProcess
();
when
(
process
.
stdout
).
thenAnswer
((
_
)
=>
stdoutStream
);
when
(
process
.
stderr
).
thenAnswer
((
_
)
=>
stderrStream
);
when
(
process
.
exitCode
).
thenAnswer
((
_
)
=>
Future
<
int
>.
value
(
exitCode
));
return
process
;
}
import
'../src/mocks.dart'
;
void
main
(
)
{
group
(
'channel'
,
()
{
...
...
packages/flutter_tools/test/general.shard/commands/build_apk_test.dart
View file @
f098de1f
...
...
@@ -2,15 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:io'
;
import
'package:args/command_runner.dart'
;
import
'package:flutter_tools/src/android/android_builder.dart'
;
import
'package:flutter_tools/src/android/android_sdk.dart'
;
import
'package:flutter_tools/src/android/gradle.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/platform.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/commands/build_apk.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/reporting/reporting.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:process/process.dart'
;
import
'../../src/common.dart'
;
import
'../../src/context.dart'
;
import
'../../src/mocks.dart'
;
void
main
(
)
{
Cache
.
disableLocking
();
...
...
@@ -26,21 +35,10 @@ void main() {
tryToDelete
(
tempDir
);
});
Future
<
BuildApkCommand
>
runCommandIn
(
String
target
,
{
List
<
String
>
arguments
})
async
{
final
BuildApkCommand
command
=
BuildApkCommand
();
final
CommandRunner
<
void
>
runner
=
createTestCommandRunner
(
command
);
await
runner
.
run
(<
String
>[
'apk'
,
...?
arguments
,
fs
.
path
.
join
(
target
,
'lib'
,
'main.dart'
),
]);
return
command
;
}
testUsingContext
(
'indicate the default target platforms'
,
()
async
{
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
]);
final
BuildApkCommand
command
=
await
run
CommandIn
(
projectPath
);
final
BuildApkCommand
command
=
await
run
BuildApkCommand
(
projectPath
);
expect
(
await
command
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildApkTargetPlatform
,
'android-arm,android-arm64'
));
...
...
@@ -53,12 +51,12 @@ void main() {
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
]);
final
BuildApkCommand
commandWithFlag
=
await
run
CommandIn
(
projectPath
,
final
BuildApkCommand
commandWithFlag
=
await
run
BuildApkCommand
(
projectPath
,
arguments:
<
String
>[
'--split-per-abi'
]);
expect
(
await
commandWithFlag
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildApkSplitPerAbi
,
'true'
));
final
BuildApkCommand
commandWithoutFlag
=
await
run
CommandIn
(
projectPath
);
final
BuildApkCommand
commandWithoutFlag
=
await
run
BuildApkCommand
(
projectPath
);
expect
(
await
commandWithoutFlag
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildApkSplitPerAbi
,
'false'
));
...
...
@@ -70,21 +68,21 @@ void main() {
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
]);
final
BuildApkCommand
commandDefault
=
await
run
CommandIn
(
projectPath
);
final
BuildApkCommand
commandDefault
=
await
run
BuildApkCommand
(
projectPath
);
expect
(
await
commandDefault
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildApkBuildMode
,
'release'
));
final
BuildApkCommand
commandInRelease
=
await
run
CommandIn
(
projectPath
,
final
BuildApkCommand
commandInRelease
=
await
run
BuildApkCommand
(
projectPath
,
arguments:
<
String
>[
'--release'
]);
expect
(
await
commandInRelease
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildApkBuildMode
,
'release'
));
final
BuildApkCommand
commandInDebug
=
await
run
CommandIn
(
projectPath
,
final
BuildApkCommand
commandInDebug
=
await
run
BuildApkCommand
(
projectPath
,
arguments:
<
String
>[
'--debug'
]);
expect
(
await
commandInDebug
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildApkBuildMode
,
'debug'
));
final
BuildApkCommand
commandInProfile
=
await
run
CommandIn
(
projectPath
,
final
BuildApkCommand
commandInProfile
=
await
run
BuildApkCommand
(
projectPath
,
arguments:
<
String
>[
'--profile'
]);
expect
(
await
commandInProfile
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildApkBuildMode
,
'profile'
));
...
...
@@ -93,4 +91,201 @@ void main() {
AndroidBuilder:
()
=>
FakeAndroidBuilder
(),
},
timeout:
allowForCreateFlutterProject
);
});
group
(
'Gradle'
,
()
{
Directory
tempDir
;
ProcessManager
mockProcessManager
;
String
gradlew
;
AndroidSdk
mockAndroidSdk
;
Usage
mockUsage
;
setUp
(()
{
mockUsage
=
MockUsage
();
when
(
mockUsage
.
isFirstRun
).
thenReturn
(
true
);
tempDir
=
fs
.
systemTempDirectory
.
createTempSync
(
'flutter_tools_packages_test.'
);
gradlew
=
fs
.
path
.
join
(
tempDir
.
path
,
'flutter_project'
,
'android'
,
platform
.
isWindows
?
'gradlew.bat'
:
'gradlew'
);
mockProcessManager
=
MockProcessManager
();
when
(
mockProcessManager
.
run
(<
String
>[
gradlew
,
'-v'
],
environment:
anyNamed
(
'environment'
)))
.
thenAnswer
((
_
)
=>
Future
<
ProcessResult
>.
value
(
ProcessResult
(
0
,
0
,
''
,
''
)));
when
(
mockProcessManager
.
run
(<
String
>[
gradlew
,
'app:properties'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
)))
.
thenAnswer
((
_
)
=>
Future
<
ProcessResult
>.
value
(
ProcessResult
(
0
,
0
,
'buildDir: irrelevant'
,
''
)));
when
(
mockProcessManager
.
run
(<
String
>[
gradlew
,
'app:tasks'
,
'--all'
,
'--console=auto'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
)))
.
thenAnswer
((
_
)
=>
Future
<
ProcessResult
>.
value
(
ProcessResult
(
0
,
0
,
'assembleRelease'
,
''
)));
// Fallback with error.
final
Process
process
=
createMockProcess
(
exitCode:
1
);
when
(
mockProcessManager
.
start
(
any
,
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
)))
.
thenAnswer
((
_
)
=>
Future
<
Process
>.
value
(
process
));
when
(
mockProcessManager
.
canRun
(
any
)).
thenReturn
(
false
);
mockAndroidSdk
=
MockAndroidSdk
();
when
(
mockAndroidSdk
.
directory
).
thenReturn
(
'irrelevant'
);
});
tearDown
(()
{
tryToDelete
(
tempDir
);
});
testUsingContext
(
'proguard is enabled by default on release mode'
,
()
async
{
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
]);
await
expectLater
(()
async
{
await
runBuildApkCommand
(
projectPath
);
},
throwsToolExit
(
message:
'Gradle task assembleRelease failed with exit code 1'
));
verify
(
mockProcessManager
.
start
(
<
String
>[
gradlew
,
'-q'
,
'-Ptarget=
${fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptrack-widget-creation=false'
,
'-Pproguard=true'
,
'-Ptarget-platform=android-arm,android-arm64'
,
'assembleRelease'
,
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
AndroidSdk:
()
=>
mockAndroidSdk
,
FlutterProjectFactory:
()
=>
FakeFlutterProjectFactory
(
tempDir
),
GradleUtils:
()
=>
GradleUtils
(),
ProcessManager:
()
=>
mockProcessManager
,
},
timeout:
allowForCreateFlutterProject
);
testUsingContext
(
'proguard is disabled when --no-proguard is passed'
,
()
async
{
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
]);
await
expectLater
(()
async
{
await
runBuildApkCommand
(
projectPath
,
arguments:
<
String
>[
'--no-proguard'
],
);
},
throwsToolExit
(
message:
'Gradle task assembleRelease failed with exit code 1'
));
verify
(
mockProcessManager
.
start
(
<
String
>[
gradlew
,
'-q'
,
'-Ptarget=
${fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptrack-widget-creation=false'
,
'-Ptarget-platform=android-arm,android-arm64'
,
'assembleRelease'
,
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
AndroidSdk:
()
=>
mockAndroidSdk
,
FlutterProjectFactory:
()
=>
FakeFlutterProjectFactory
(
tempDir
),
GradleUtils:
()
=>
GradleUtils
(),
ProcessManager:
()
=>
mockProcessManager
,
},
timeout:
allowForCreateFlutterProject
);
testUsingContext
(
'guides the user when proguard fails'
,
()
async
{
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
]);
when
(
mockProcessManager
.
start
(
<
String
>[
gradlew
,
'-q'
,
'-Ptarget=
${fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptrack-widget-creation=false'
,
'-Pproguard=true'
,
'-Ptarget-platform=android-arm,android-arm64'
,
'assembleRelease'
,
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
thenAnswer
((
_
)
{
const
String
proguardStdoutWarning
=
'Warning: there were 6 unresolved references to program class members.'
'Your input classes appear to be inconsistent.'
'You may need to recompile the code.'
'(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)'
;
return
Future
<
Process
>.
value
(
createMockProcess
(
exitCode:
1
,
stdout:
proguardStdoutWarning
,
)
);
});
await
expectLater
(()
async
{
await
runBuildApkCommand
(
projectPath
,
);
},
throwsToolExit
(
message:
'Gradle task assembleRelease failed with exit code 1'
));
expect
(
testLogger
.
statusText
,
contains
(
'Proguard may have failed to optimize the Java bytecode.'
));
expect
(
testLogger
.
statusText
,
contains
(
'To disable proguard, pass the `--no-proguard` flag to this command.'
));
expect
(
testLogger
.
statusText
,
contains
(
'To learn more about Proguard, see: https://flutter.dev/docs/deployment/android#enabling-proguard'
));
verify
(
mockUsage
.
sendEvent
(
'build-apk'
,
'proguard-failure'
,
parameters:
anyNamed
(
'parameters'
),
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
AndroidSdk:
()
=>
mockAndroidSdk
,
GradleUtils:
()
=>
GradleUtils
(),
FlutterProjectFactory:
()
=>
FakeFlutterProjectFactory
(
tempDir
),
ProcessManager:
()
=>
mockProcessManager
,
Usage:
()
=>
mockUsage
,
},
timeout:
allowForCreateFlutterProject
);
});
}
Future
<
BuildApkCommand
>
runBuildApkCommand
(
String
target
,
{
List
<
String
>
arguments
}
)
async
{
final
BuildApkCommand
command
=
BuildApkCommand
();
final
CommandRunner
<
void
>
runner
=
createTestCommandRunner
(
command
);
await
runner
.
run
(<
String
>[
'apk'
,
...?
arguments
,
fs
.
path
.
join
(
target
,
'lib'
,
'main.dart'
),
]);
return
command
;
}
class
FakeFlutterProjectFactory
extends
FlutterProjectFactory
{
FakeFlutterProjectFactory
(
this
.
directoryOverride
)
:
assert
(
directoryOverride
!=
null
);
final
Directory
directoryOverride
;
@override
FlutterProject
fromDirectory
(
Directory
_
)
{
return
super
.
fromDirectory
(
directoryOverride
.
childDirectory
(
'flutter_project'
));
}
}
class
MockAndroidSdk
extends
Mock
implements
AndroidSdk
{}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{}
class
MockProcess
extends
Mock
implements
Process
{}
class
MockUsage
extends
Mock
implements
Usage
{}
packages/flutter_tools/test/general.shard/commands/build_appbundle_test.dart
View file @
f098de1f
...
...
@@ -2,15 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:io'
;
import
'package:args/command_runner.dart'
;
import
'package:flutter_tools/src/android/android_builder.dart'
;
import
'package:flutter_tools/src/android/android_sdk.dart'
;
import
'package:flutter_tools/src/android/gradle.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/platform.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/commands/build_appbundle.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/reporting/reporting.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:process/process.dart'
;
import
'../../src/common.dart'
;
import
'../../src/context.dart'
;
import
'../../src/mocks.dart'
;
void
main
(
)
{
Cache
.
disableLocking
();
...
...
@@ -26,21 +35,10 @@ void main() {
tryToDelete
(
tempDir
);
});
Future
<
BuildAppBundleCommand
>
runCommandIn
(
String
target
,
{
List
<
String
>
arguments
})
async
{
final
BuildAppBundleCommand
command
=
BuildAppBundleCommand
();
final
CommandRunner
<
void
>
runner
=
createTestCommandRunner
(
command
);
await
runner
.
run
(<
String
>[
'appbundle'
,
...?
arguments
,
fs
.
path
.
join
(
target
,
'lib'
,
'main.dart'
),
]);
return
command
;
}
testUsingContext
(
'indicate the default target platforms'
,
()
async
{
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
]);
final
BuildAppBundleCommand
command
=
await
run
CommandIn
(
projectPath
);
final
BuildAppBundleCommand
command
=
await
run
BuildAppBundleCommand
(
projectPath
);
expect
(
await
command
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildAppBundleTargetPlatform
,
'android-arm,android-arm64'
));
...
...
@@ -53,21 +51,21 @@ void main() {
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
]);
final
BuildAppBundleCommand
commandDefault
=
await
run
CommandIn
(
projectPath
);
final
BuildAppBundleCommand
commandDefault
=
await
run
BuildAppBundleCommand
(
projectPath
);
expect
(
await
commandDefault
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildAppBundleBuildMode
,
'release'
));
final
BuildAppBundleCommand
commandInRelease
=
await
run
CommandIn
(
projectPath
,
final
BuildAppBundleCommand
commandInRelease
=
await
run
BuildAppBundleCommand
(
projectPath
,
arguments:
<
String
>[
'--release'
]);
expect
(
await
commandInRelease
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildAppBundleBuildMode
,
'release'
));
final
BuildAppBundleCommand
commandInDebug
=
await
run
CommandIn
(
projectPath
,
final
BuildAppBundleCommand
commandInDebug
=
await
run
BuildAppBundleCommand
(
projectPath
,
arguments:
<
String
>[
'--debug'
]);
expect
(
await
commandInDebug
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildAppBundleBuildMode
,
'debug'
));
final
BuildAppBundleCommand
commandInProfile
=
await
run
CommandIn
(
projectPath
,
final
BuildAppBundleCommand
commandInProfile
=
await
run
BuildAppBundleCommand
(
projectPath
,
arguments:
<
String
>[
'--profile'
]);
expect
(
await
commandInProfile
.
usageValues
,
containsPair
(
CustomDimensions
.
commandBuildAppBundleBuildMode
,
'profile'
));
...
...
@@ -76,4 +74,207 @@ void main() {
AndroidBuilder:
()
=>
FakeAndroidBuilder
(),
},
timeout:
allowForCreateFlutterProject
);
});
group
(
'Flags'
,
()
{
Directory
tempDir
;
ProcessManager
mockProcessManager
;
MockAndroidSdk
mockAndroidSdk
;
String
gradlew
;
Usage
mockUsage
;
setUp
(()
{
mockUsage
=
MockUsage
();
when
(
mockUsage
.
isFirstRun
).
thenReturn
(
true
);
tempDir
=
fs
.
systemTempDirectory
.
createTempSync
(
'flutter_tools_packages_test.'
);
gradlew
=
fs
.
path
.
join
(
tempDir
.
path
,
'flutter_project'
,
'android'
,
platform
.
isWindows
?
'gradlew.bat'
:
'gradlew'
);
mockProcessManager
=
MockProcessManager
();
when
(
mockProcessManager
.
run
(<
String
>[
gradlew
,
'-v'
],
environment:
anyNamed
(
'environment'
)))
.
thenAnswer
((
_
)
=>
Future
<
ProcessResult
>.
value
(
ProcessResult
(
0
,
0
,
''
,
''
)));
when
(
mockProcessManager
.
run
(<
String
>[
gradlew
,
'app:properties'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
)))
.
thenAnswer
((
_
)
=>
Future
<
ProcessResult
>.
value
(
ProcessResult
(
0
,
0
,
'buildDir: irrelevant'
,
''
)));
when
(
mockProcessManager
.
run
(<
String
>[
gradlew
,
'app:tasks'
,
'--all'
,
'--console=auto'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
)))
.
thenAnswer
((
_
)
=>
Future
<
ProcessResult
>.
value
(
ProcessResult
(
0
,
0
,
'assembleRelease'
,
''
)));
// Fallback with error.
final
Process
process
=
createMockProcess
(
exitCode:
1
);
when
(
mockProcessManager
.
start
(
any
,
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
)))
.
thenAnswer
((
_
)
=>
Future
<
Process
>.
value
(
process
));
when
(
mockProcessManager
.
canRun
(
any
)).
thenReturn
(
false
);
mockAndroidSdk
=
MockAndroidSdk
();
when
(
mockAndroidSdk
.
validateSdkWellFormed
()).
thenReturn
(
const
<
String
>[]);
when
(
mockAndroidSdk
.
directory
).
thenReturn
(
'irrelevant'
);
});
tearDown
(()
{
tryToDelete
(
tempDir
);
});
testUsingContext
(
'proguard is enabled by default on release mode'
,
()
async
{
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
],
);
await
expectLater
(()
async
{
await
runBuildAppBundleCommand
(
projectPath
);
},
throwsToolExit
(
message:
'Gradle task bundleRelease failed with exit code 1'
));
verify
(
mockProcessManager
.
start
(
<
String
>[
gradlew
,
'-q'
,
'-Ptarget=
${fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptrack-widget-creation=false'
,
'-Pproguard=true'
,
'-Ptarget-platform=android-arm,android-arm64'
,
'bundleRelease'
,
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
AndroidSdk:
()
=>
mockAndroidSdk
,
FlutterProjectFactory:
()
=>
FakeFlutterProjectFactory
(
tempDir
),
GradleUtils:
()
=>
GradleUtils
(),
ProcessManager:
()
=>
mockProcessManager
,
},
timeout:
allowForCreateFlutterProject
);
testUsingContext
(
'proguard is disabled when --no-proguard is passed'
,
()
async
{
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
],
);
await
expectLater
(()
async
{
await
runBuildAppBundleCommand
(
projectPath
,
arguments:
<
String
>[
'--no-proguard'
],
);
},
throwsToolExit
(
message:
'Gradle task bundleRelease failed with exit code 1'
));
verify
(
mockProcessManager
.
start
(
<
String
>[
gradlew
,
'-q'
,
'-Ptarget=
${fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptrack-widget-creation=false'
,
'-Ptarget-platform=android-arm,android-arm64'
,
'bundleRelease'
,
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
AndroidSdk:
()
=>
mockAndroidSdk
,
FlutterProjectFactory:
()
=>
FakeFlutterProjectFactory
(
tempDir
),
GradleUtils:
()
=>
GradleUtils
(),
ProcessManager:
()
=>
mockProcessManager
,
},
timeout:
allowForCreateFlutterProject
);
testUsingContext
(
'guides the user when proguard fails'
,
()
async
{
final
String
projectPath
=
await
createProject
(
tempDir
,
arguments:
<
String
>[
'--no-pub'
,
'--template=app'
]);
when
(
mockProcessManager
.
start
(
<
String
>[
gradlew
,
'-q'
,
'-Ptarget=
${fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}
'
,
'-Ptrack-widget-creation=false'
,
'-Pproguard=true'
,
'-Ptarget-platform=android-arm,android-arm64'
,
'bundleRelease'
,
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
),
)).
thenAnswer
((
_
)
{
const
String
proguardStdoutWarning
=
'Warning: there were 6 unresolved references to program class members.'
'Your input classes appear to be inconsistent.'
'You may need to recompile the code.'
'(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)'
;
return
Future
<
Process
>.
value
(
createMockProcess
(
exitCode:
1
,
stdout:
proguardStdoutWarning
,
)
);
});
await
expectLater
(()
async
{
await
runBuildAppBundleCommand
(
projectPath
,
);
},
throwsToolExit
(
message:
'Gradle task bundleRelease failed with exit code 1'
));
expect
(
testLogger
.
statusText
,
contains
(
'Proguard may have failed to optimize the Java bytecode.'
));
expect
(
testLogger
.
statusText
,
contains
(
'To disable proguard, pass the `--no-proguard` flag to this command.'
));
expect
(
testLogger
.
statusText
,
contains
(
'To learn more about Proguard, see: https://flutter.dev/docs/deployment/android#enabling-proguard'
));
verify
(
mockUsage
.
sendEvent
(
'build-appbundle'
,
'proguard-failure'
,
parameters:
anyNamed
(
'parameters'
),
)).
called
(
1
);
},
overrides:
<
Type
,
Generator
>{
AndroidSdk:
()
=>
mockAndroidSdk
,
GradleUtils:
()
=>
GradleUtils
(),
FlutterProjectFactory:
()
=>
FakeFlutterProjectFactory
(
tempDir
),
ProcessManager:
()
=>
mockProcessManager
,
Usage:
()
=>
mockUsage
,
},
timeout:
allowForCreateFlutterProject
);
});
}
Future
<
BuildAppBundleCommand
>
runBuildAppBundleCommand
(
String
target
,
{
List
<
String
>
arguments
}
)
async
{
final
BuildAppBundleCommand
command
=
BuildAppBundleCommand
();
final
CommandRunner
<
void
>
runner
=
createTestCommandRunner
(
command
);
await
runner
.
run
(<
String
>[
'appbundle'
,
...?
arguments
,
fs
.
path
.
join
(
target
,
'lib'
,
'main.dart'
),
]);
return
command
;
}
class
FakeFlutterProjectFactory
extends
FlutterProjectFactory
{
FakeFlutterProjectFactory
(
this
.
_directoryOverride
)
:
assert
(
_directoryOverride
!=
null
);
final
Directory
_directoryOverride
;
@override
FlutterProject
fromDirectory
(
Directory
_
)
{
return
super
.
fromDirectory
(
_directoryOverride
.
childDirectory
(
'flutter_project'
));
}
}
class
MockAndroidSdk
extends
Mock
implements
AndroidSdk
{}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{}
class
MockProcess
extends
Mock
implements
Process
{}
class
MockUsage
extends
Mock
implements
Usage
{}
packages/flutter_tools/test/general.shard/commands/upgrade_test.dart
View file @
f098de1f
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:convert'
;
import
'package:flutter_tools/src/base/common.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
...
...
@@ -17,21 +15,7 @@ import 'package:process/process.dart';
import
'../../src/common.dart'
;
import
'../../src/context.dart'
;
Process
createMockProcess
(
{
int
exitCode
=
0
,
String
stdout
=
''
,
String
stderr
=
''
})
{
final
Stream
<
List
<
int
>>
stdoutStream
=
Stream
<
List
<
int
>>.
fromIterable
(<
List
<
int
>>[
utf8
.
encode
(
stdout
),
]);
final
Stream
<
List
<
int
>>
stderrStream
=
Stream
<
List
<
int
>>.
fromIterable
(<
List
<
int
>>[
utf8
.
encode
(
stderr
),
]);
final
Process
process
=
MockProcess
();
when
(
process
.
stdout
).
thenAnswer
((
_
)
=>
stdoutStream
);
when
(
process
.
stderr
).
thenAnswer
((
_
)
=>
stderrStream
);
when
(
process
.
exitCode
).
thenAnswer
((
_
)
=>
Future
<
int
>.
value
(
exitCode
));
return
process
;
}
import
'../../src/mocks.dart'
;
void
main
(
)
{
group
(
'UpgradeCommandRunner'
,
()
{
...
...
packages/flutter_tools/test/src/common.dart
View file @
f098de1f
...
...
@@ -116,6 +116,8 @@ Future<String> createProject(Directory temp, { List<String> arguments }) async {
final
CreateCommand
command
=
CreateCommand
();
final
CommandRunner
<
void
>
runner
=
createTestCommandRunner
(
command
);
await
runner
.
run
(<
String
>[
'create'
,
...
arguments
,
projectPath
]);
// Created `.packages` since it's not created when the flag `--no-pub` is passed.
fs
.
file
(
fs
.
path
.
join
(
projectPath
,
'.packages'
)).
createSync
();
return
projectPath
;
}
...
...
packages/flutter_tools/test/src/mocks.dart
View file @
f098de1f
...
...
@@ -221,6 +221,24 @@ ProcessFactory flakyProcessFactory({
};
}
/// Creates a mock process that returns with the given [exitCode], [stdout] and [stderr].
Process
createMockProcess
(
{
int
exitCode
=
0
,
String
stdout
=
''
,
String
stderr
=
''
})
{
final
Stream
<
List
<
int
>>
stdoutStream
=
Stream
<
List
<
int
>>.
fromIterable
(<
List
<
int
>>[
utf8
.
encode
(
stdout
),
]);
final
Stream
<
List
<
int
>>
stderrStream
=
Stream
<
List
<
int
>>.
fromIterable
(<
List
<
int
>>[
utf8
.
encode
(
stderr
),
]);
final
Process
process
=
MockBasicProcess
();
when
(
process
.
stdout
).
thenAnswer
((
_
)
=>
stdoutStream
);
when
(
process
.
stderr
).
thenAnswer
((
_
)
=>
stderrStream
);
when
(
process
.
exitCode
).
thenAnswer
((
_
)
=>
Future
<
int
>.
value
(
exitCode
));
return
process
;
}
class
MockBasicProcess
extends
Mock
implements
Process
{}
/// A process that exits successfully with no output and ignores all input.
class
MockProcess
extends
Mock
implements
Process
{
MockProcess
({
...
...
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