@@ -10,6 +10,7 @@ import 'package:meta/meta.dart';
10
10
import '../android/android_sdk.dart' ;
11
11
import '../artifacts.dart' ;
12
12
import '../base/common.dart' ;
13
+ import '../base/context.dart' ;
13
14
import '../base/file_system.dart' ;
14
15
import '../base/logger.dart' ;
15
16
import '../base/os.dart' ;
@@ -28,11 +29,39 @@ import '../reporting/reporting.dart';
28
29
import 'android_sdk.dart' ;
29
30
import 'android_studio.dart' ;
30
31
31
- final RegExp _assembleTaskPattern = RegExp (r'assemble(\S+)' );
32
+ /// Gradle utils in the current [AppContext] .
33
+ GradleUtils get gradleUtils => context.get <GradleUtils >();
34
+
35
+ /// Provides utilities to run a Gradle task,
36
+ /// such as finding the Gradle executable or constructing a Gradle project.
37
+ class GradleUtils {
38
+ /// Empty constructor.
39
+ GradleUtils ();
40
+
41
+ String _cachedExecutable;
42
+ /// Gets the Gradle executable path.
43
+ /// This is the `gradlew` or `gradlew.bat` script in the `android/` directory.
44
+ Future <String > getExecutable (FlutterProject project) async {
45
+ _cachedExecutable ?? = await _initializeGradle (project);
46
+ return _cachedExecutable;
47
+ }
48
+
49
+ GradleProject _cachedAppProject;
50
+ /// Gets the [GradleProject] for the current [FlutterProject] if built as an app.
51
+ Future <GradleProject > get appProject async {
52
+ _cachedAppProject ?? = await _readGradleProject (isLibrary: false );
53
+ return _cachedAppProject;
54
+ }
32
55
33
- GradleProject _cachedGradleAppProject;
34
- GradleProject _cachedGradleLibraryProject;
35
- String _cachedGradleExecutable;
56
+ GradleProject _cachedLibraryProject;
57
+ /// Gets the [GradleProject] for the current [FlutterProject] if built as a library.
58
+ Future <GradleProject > get libraryProject async {
59
+ _cachedLibraryProject ?? = await _readGradleProject (isLibrary: true );
60
+ return _cachedLibraryProject;
61
+ }
62
+ }
63
+
64
+ final RegExp _assembleTaskPattern = RegExp (r'assemble(\S+)' );
36
65
37
66
enum FlutterPluginVersion {
38
67
none,
@@ -103,29 +132,20 @@ Future<File> getGradleAppOut(AndroidProject androidProject) async {
103
132
case FlutterPluginVersion .managed:
104
133
// Fall through. The managed plugin matches plugin v2 for now.
105
134
case FlutterPluginVersion .v2:
106
- return fs.file ((await _gradleAppProject ()).apkDirectory.childFile ('app.apk' ));
135
+ final GradleProject gradleProject = await gradleUtils.appProject;
136
+ return fs.file (gradleProject.apkDirectory.childFile ('app.apk' ));
107
137
}
108
138
return null ;
109
139
}
110
140
111
- Future <GradleProject > _gradleAppProject () async {
112
- _cachedGradleAppProject ?? = await _readGradleProject (isLibrary: false );
113
- return _cachedGradleAppProject;
114
- }
115
-
116
- Future <GradleProject > _gradleLibraryProject () async {
117
- _cachedGradleLibraryProject ?? = await _readGradleProject (isLibrary: true );
118
- return _cachedGradleLibraryProject;
119
- }
120
-
121
141
/// Runs `gradlew dependencies` , ensuring that dependencies are resolved and
122
142
/// potentially downloaded.
123
143
Future <void > checkGradleDependencies () async {
124
144
final Status progress = logger.startProgress ('Ensuring gradle dependencies are up to date...' , timeout: timeoutConfiguration.slowOperation);
125
145
final FlutterProject flutterProject = FlutterProject .current ();
126
- final String gradle = await _ensureGradle (flutterProject);
146
+ final String gradlew = await gradleUtils. getExecutable (flutterProject);
127
147
await runCheckedAsync (
128
- < String > [gradle , 'dependencies' ],
148
+ < String > [gradlew , 'dependencies' ],
129
149
workingDirectory: flutterProject.android.hostAppGradleRoot.path,
130
150
environment: _gradleEnv,
131
151
);
@@ -189,7 +209,8 @@ void createSettingsAarGradle(Directory androidDirectory) {
189
209
// of calculating the app properties using Gradle. This may take minutes.
190
210
Future <GradleProject > _readGradleProject ({bool isLibrary = false }) async {
191
211
final FlutterProject flutterProject = FlutterProject .current ();
192
- final String gradle = await _ensureGradle (flutterProject);
212
+ final String gradlew = await gradleUtils.getExecutable (flutterProject);
213
+
193
214
updateLocalProperties (project: flutterProject);
194
215
195
216
final FlutterManifest manifest = flutterProject.manifest;
@@ -213,12 +234,12 @@ Future<GradleProject> _readGradleProject({bool isLibrary = false}) async {
213
234
// flavors and build types defined in the project. If gradle fails, then check if the failure is due to t
214
235
try {
215
236
final RunResult propertiesRunResult = await runCheckedAsync (
216
- < String > [gradle , isLibrary ? 'properties' : 'app:properties' ],
237
+ < String > [gradlew , isLibrary ? 'properties' : 'app:properties' ],
217
238
workingDirectory: hostAppGradleRoot.path,
218
239
environment: _gradleEnv,
219
240
);
220
241
final RunResult tasksRunResult = await runCheckedAsync (
221
- < String > [gradle , isLibrary ? 'tasks' : 'app:tasks' , '--all' , '--console=auto' ],
242
+ < String > [gradlew , isLibrary ? 'tasks' : 'app:tasks' , '--all' , '--console=auto' ],
222
243
workingDirectory: hostAppGradleRoot.path,
223
244
environment: _gradleEnv,
224
245
);
@@ -274,11 +295,6 @@ String _locateGradlewExecutable(Directory directory) {
274
295
return null ;
275
296
}
276
297
277
- Future <String > _ensureGradle (FlutterProject project) async {
278
- _cachedGradleExecutable ?? = await _initializeGradle (project);
279
- return _cachedGradleExecutable;
280
- }
281
-
282
298
// Note: Gradle may be bootstrapped and possibly downloaded as a side-effect
283
299
// of validating the Gradle executable. This may take several seconds.
284
300
Future <String > _initializeGradle (FlutterProject project) async {
@@ -492,17 +508,15 @@ Future<void> buildGradleProject({
492
508
// from the local.properties file.
493
509
updateLocalProperties (project: project, buildInfo: androidBuildInfo.buildInfo);
494
510
495
- final String gradle = await _ensureGradle (project);
496
-
497
511
switch (getFlutterPluginVersion (project.android)) {
498
512
case FlutterPluginVersion .none:
499
513
// Fall through. Pretend it's v1, and just go for it.
500
514
case FlutterPluginVersion .v1:
501
- return _buildGradleProjectV1 (project, gradle );
515
+ return _buildGradleProjectV1 (project);
502
516
case FlutterPluginVersion .managed:
503
517
// Fall through. Managed plugin builds the same way as plugin v2.
504
518
case FlutterPluginVersion .v2:
505
- return _buildGradleProjectV2 (project, gradle, androidBuildInfo, target, isBuildingBundle);
519
+ return _buildGradleProjectV2 (project, androidBuildInfo, target, isBuildingBundle);
506
520
}
507
521
}
508
522
@@ -516,9 +530,9 @@ Future<void> buildGradleAar({
516
530
517
531
GradleProject gradleProject;
518
532
if (manifest.isModule) {
519
- gradleProject = await _gradleAppProject () ;
533
+ gradleProject = await gradleUtils.appProject ;
520
534
} else if (manifest.isPlugin) {
521
- gradleProject = await _gradleLibraryProject () ;
535
+ gradleProject = await gradleUtils.libraryProject ;
522
536
} else {
523
537
throwToolExit ('AARs can only be built for plugin or module projects.' );
524
538
}
@@ -538,12 +552,11 @@ Future<void> buildGradleAar({
538
552
multilineOutput: true ,
539
553
);
540
554
541
- final String gradle = await _ensureGradle (project);
542
- final String gradlePath = fs.file (gradle).absolute.path;
555
+ final String gradlew = await gradleUtils.getExecutable (project);
543
556
final String flutterRoot = fs.path.absolute (Cache .flutterRoot);
544
557
final String initScript = fs.path.join (flutterRoot, 'packages' ,'flutter_tools' , 'gradle' , 'aar_init_script.gradle' );
545
558
final List <String > command = < String > [
546
- gradlePath ,
559
+ gradlew ,
547
560
'-I=$initScript ' ,
548
561
'-Pflutter-root=$flutterRoot ' ,
549
562
'-Poutput-dir=${gradleProject .buildDirectory }' ,
@@ -601,7 +614,8 @@ Future<void> buildGradleAar({
601
614
printStatus ('Built ${fs .path .relative (repoDirectory .path )}.' , color: TerminalColor .green);
602
615
}
603
616
604
- Future <void > _buildGradleProjectV1 (FlutterProject project, String gradle) async {
617
+ Future <void > _buildGradleProjectV1 (FlutterProject project) async {
618
+ final String gradlew = await gradleUtils.getExecutable (project);
605
619
// Run 'gradlew build'.
606
620
final Status status = logger.startProgress (
607
621
'Running \' gradlew build\' ...' ,
@@ -610,7 +624,7 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async
610
624
);
611
625
final Stopwatch sw = Stopwatch ()..start ();
612
626
final int exitCode = await runCommandAndStreamOutput (
613
- < String > [fs.file (gradle ).absolute.path, 'build' ],
627
+ < String > [fs.file (gradlew ).absolute.path, 'build' ],
614
628
workingDirectory: project.android.hostAppGradleRoot.path,
615
629
allowReentrantFlutter: true ,
616
630
environment: _gradleEnv,
@@ -661,12 +675,12 @@ void printUndefinedTask(GradleProject project, BuildInfo buildInfo) {
661
675
662
676
Future <void > _buildGradleProjectV2 (
663
677
FlutterProject flutterProject,
664
- String gradle,
665
678
AndroidBuildInfo androidBuildInfo,
666
679
String target,
667
680
bool isBuildingBundle,
668
681
) async {
669
- final GradleProject project = await _gradleAppProject ();
682
+ final String gradlew = await gradleUtils.getExecutable (flutterProject);
683
+ final GradleProject project = await gradleUtils.appProject;
670
684
final BuildInfo buildInfo = androidBuildInfo.buildInfo;
671
685
672
686
String assembleTask;
@@ -685,8 +699,7 @@ Future<void> _buildGradleProjectV2(
685
699
timeout: timeoutConfiguration.slowOperation,
686
700
multilineOutput: true ,
687
701
);
688
- final String gradlePath = fs.file (gradle).absolute.path;
689
- final List <String > command = < String > [gradlePath];
702
+ final List <String > command = < String > [gradlew];
690
703
if (logger.isVerbose) {
691
704
command.add ('-Pverbose=true' );
692
705
} else {
@@ -712,6 +725,8 @@ Future<void> _buildGradleProjectV2(
712
725
command.add ('-Pfilesystem-scheme=${buildInfo .fileSystemScheme }' );
713
726
if (androidBuildInfo.splitPerAbi)
714
727
command.add ('-Psplit-per-abi=true' );
728
+ if (androidBuildInfo.proguard)
729
+ command.add ('-Pproguard=true' );
715
730
if (androidBuildInfo.targetArchs.isNotEmpty) {
716
731
final String targetPlatforms = androidBuildInfo.targetArchs
717
732
.map (getPlatformNameForAndroidArch).join (',' );
@@ -727,6 +742,7 @@ Future<void> _buildGradleProjectV2(
727
742
}
728
743
command.add (assembleTask);
729
744
bool potentialAndroidXFailure = false ;
745
+ bool potentialProguardFailure = false ;
730
746
final Stopwatch sw = Stopwatch ()..start ();
731
747
int exitCode = 1 ;
732
748
try {
@@ -743,13 +759,17 @@ Future<void> _buildGradleProjectV2(
743
759
if (! isAndroidXPluginWarning && androidXFailureRegex.hasMatch (line)) {
744
760
potentialAndroidXFailure = true ;
745
761
}
762
+ // Proguard errors include this url.
763
+ if (! potentialProguardFailure && androidBuildInfo.proguard &&
764
+ line.contains ('http://proguard.sourceforge.net' )) {
765
+ potentialProguardFailure = true ;
766
+ }
746
767
// Always print the full line in verbose mode.
747
768
if (logger.isVerbose) {
748
769
return line;
749
770
} else if (isAndroidXPluginWarning || ! ndkMessageFilter.hasMatch (line)) {
750
771
return null ;
751
772
}
752
-
753
773
return line;
754
774
},
755
775
);
@@ -758,7 +778,13 @@ Future<void> _buildGradleProjectV2(
758
778
}
759
779
760
780
if (exitCode != 0 ) {
761
- if (potentialAndroidXFailure) {
781
+ if (potentialProguardFailure) {
782
+ final String exclamationMark = terminal.color ('[!]' , TerminalColor .red);
783
+ printStatus ('$exclamationMark Proguard may have failed to optimize the Java bytecode.' , emphasis: true );
784
+ printStatus ('To disable proguard, pass the `--no-proguard` flag to this command.' , indent: 4 );
785
+ printStatus ('To learn more about Proguard, see: https://flutter.dev/docs/deployment/android#enabling-proguard' , indent: 4 );
786
+ BuildEvent ('proguard-failure' ).send ();
787
+ } else if (potentialAndroidXFailure) {
762
788
printStatus ('AndroidX incompatibilities may have caused this build to fail. See https://goo.gl/CP92wY.' );
763
789
BuildEvent ('android-x-failure' ).send ();
764
790
}
0 commit comments