Skip to content

Commit b2de4df

Browse files
authored
Re-land "Ensure flutter build apk --release optimizes+shrinks platform code" (#153868)
Re-lands flutter/flutter#136880, fixes flutter/flutter#136879. Additions to/things that are different from the original PR: - Adds an entry to `gradle_errors.dart` that tells people when they run into the R8 bug because of using AGP 7.3.0 (https://issuetracker.google.com/issues/242308990). - Previous PR moved templates off of AGP 7.3.0. - Packages repo has been moved off AGP 7.3.0 (#7432). Also, unrelatedly: - Deletes an entry in `gradle_errors.dart` that informed people to build with `--no-shrink`. This flag [doesn't do anything](flutter/website#11022 (comment)), so it can't be the solution to any error. - Uniquely lowers the priority of the `incompatibleKotlinVersionHandler`. This is necessary because the ordering of the errors doesn't fully determine the priority of which handler we decide to use, but also the order of the log lines. The kotlin error lines often print before the other error lines, so putting it last in the list of handlers isn't sufficient to lower it to be the lowest priority handler.
1 parent 1cdff36 commit b2de4df

File tree

5 files changed

+83
-89
lines changed

5 files changed

+83
-89
lines changed

packages/flutter_tools/gradle/src/main/groovy/flutter.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ class FlutterPlugin implements Plugin<Project> {
381381
shrinkResources(isBuiltAsApp(project))
382382
// Fallback to `android/app/proguard-rules.pro`.
383383
// This way, custom Proguard rules can be configured as needed.
384-
proguardFiles(project.android.getDefaultProguardFile("proguard-android.txt"), flutterProguardRules, "proguard-rules.pro")
384+
proguardFiles(project.android.getDefaultProguardFile("proguard-android-optimize.txt"), flutterProguardRules, "proguard-rules.pro")
385385
}
386386
}
387387
}

packages/flutter_tools/lib/src/android/gradle.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,12 @@ class AndroidGradleBuilder implements AndroidBuilder {
440440
GradleHandledError? detectedGradleError;
441441
String? detectedGradleErrorLine;
442442
String? consumeLog(String line) {
443-
if (detectedGradleError != null) {
443+
// The log lines that trigger incompatibleKotlinVersionHandler don't
444+
// always indicate an error, and there are times that that handler
445+
// covers up a more important error handler. Uniquely set it to be
446+
// the lowest priority handler by allowing it to be overridden.
447+
if (detectedGradleError != null
448+
&& detectedGradleError != incompatibleKotlinVersionHandler) {
444449
// Pipe stdout/stderr from Gradle.
445450
return line;
446451
}

packages/flutter_tools/lib/src/android/gradle_errors.dart

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,10 @@ final List<GradleHandledError> gradleErrors = <GradleHandledError>[
6767
networkErrorHandler,
6868
permissionDeniedErrorHandler,
6969
flavorUndefinedHandler,
70-
r8FailureHandler,
70+
r8DexingBugInAgp73Handler,
7171
minSdkVersionHandler,
7272
transformInputIssueHandler,
7373
lockFileDepMissingHandler,
74-
incompatibleKotlinVersionHandler,
7574
minCompileSdkVersionHandler,
7675
jvm11RequiredHandler,
7776
outdatedGradleHandler,
@@ -81,6 +80,7 @@ final List<GradleHandledError> gradleErrors = <GradleHandledError>[
8180
remoteTerminatedHandshakeHandler,
8281
couldNotOpenCacheDirectoryHandler,
8382
incompatibleCompileSdk35AndAgpVersionHandler,
83+
incompatibleKotlinVersionHandler, // This handler should always be last, as its key log output is sometimes in error messages with other root causes.
8484
];
8585

8686
const String _boxTitle = 'Flutter Fix';
@@ -198,28 +198,6 @@ final GradleHandledError zipExceptionHandler = GradleHandledError(
198198
eventLabel: 'zip-exception',
199199
);
200200

201-
// R8 failure.
202-
@visibleForTesting
203-
final GradleHandledError r8FailureHandler = GradleHandledError(
204-
test: _lineMatcher(const <String>[
205-
'com.android.tools.r8',
206-
]),
207-
handler: ({
208-
required String line,
209-
required FlutterProject project,
210-
required bool usesAndroidX,
211-
}) async {
212-
globals.printBox(
213-
'${globals.logger.terminal.warningMark} The shrinker may have failed to optimize the Java bytecode.\n'
214-
'To disable the shrinker, pass the `--no-shrink` flag to this command.\n'
215-
'To learn more, see: https://developer.android.com/studio/build/shrink-code',
216-
title: _boxTitle,
217-
);
218-
return GradleBuildStatus.exit;
219-
},
220-
eventLabel: 'r8',
221-
);
222-
223201
/// Handle Gradle error thrown when Gradle needs to download additional
224202
/// Android SDK components (e.g. Platform Tools), and the license
225203
/// for that component has not been accepted.
@@ -429,7 +407,8 @@ final GradleHandledError lockFileDepMissingHandler = GradleHandledError(
429407
eventLabel: 'lock-dep-issue',
430408
);
431409

432-
@visibleForTesting
410+
// This handler is made visible in other files so that we can uniquely set it
411+
// to be the lowest priority error.
433412
final GradleHandledError incompatibleKotlinVersionHandler = GradleHandledError(
434413
test: _lineMatcher(const <String>[
435414
'was compiled with an incompatible version of Kotlin',
@@ -642,6 +621,17 @@ final GradleHandledError couldNotOpenCacheDirectoryHandler = GradleHandledError(
642621
eventLabel: 'could-not-open-cache-directory',
643622
);
644623

624+
625+
String _getAgpLocation(FlutterProject project) {
626+
return '''
627+
The version of AGP that your project uses is likely defined in:
628+
${project.android.settingsGradleFile.path},
629+
in the 'plugins' closure.
630+
Alternatively, if your project was created with an older version of the templates, it is likely
631+
in the buildscript.dependencies closure of the top-level build.gradle:
632+
${project.android.hostAppGradleFile.path}.''';
633+
}
634+
645635
@visibleForTesting
646636
final GradleHandledError incompatibleCompileSdk35AndAgpVersionHandler = GradleHandledError(
647637
test: (String line) => line.contains('RES_TABLE_TYPE_TYPE entry offsets overlap actual entry data'),
@@ -652,10 +642,7 @@ final GradleHandledError incompatibleCompileSdk35AndAgpVersionHandler = GradleHa
652642
}) async {
653643
globals.printBox(
654644
'${globals.logger.terminal.warningMark} Using compileSdk 35 requires Android Gradle Plugin (AGP) 8.1.0 or higher.'
655-
' \n Please upgrade to a newer AGP version. The version of AGP that your project uses is likely'
656-
" defined in:\n${project.android.settingsGradleFile.path},\nin the 'plugins' closure. \n Alternatively, if your "
657-
'project was created with an older version of the templates, it is likely \nin the buildscript.dependencies '
658-
'closure of the top-level build.gradle:\n${project.android.hostAppGradleFile.path}.\n\n Finally, if you have a'
645+
' \n Please upgrade to a newer AGP version.${_getAgpLocation(project)}\n\n Finally, if you have a'
659646
' strong reason to avoid upgrading AGP, you can temporarily lower the compileSdk version in the following file:\n${project.android.appGradleFile.path}',
660647
title: _boxTitle,
661648
);
@@ -664,3 +651,24 @@ final GradleHandledError incompatibleCompileSdk35AndAgpVersionHandler = GradleHa
664651
},
665652
eventLabel: 'incompatible-compile-sdk-and-agp',
666653
);
654+
655+
@visibleForTesting
656+
final GradleHandledError r8DexingBugInAgp73Handler = GradleHandledError(
657+
test: (String line) => line.contains('com.android.tools.r8.internal') && line.contains(': Unused argument with users'),
658+
handler: ({
659+
required String line,
660+
required FlutterProject project,
661+
required bool usesAndroidX,
662+
}) async {
663+
globals.printBox('''
664+
${globals.logger.terminal.warningMark} Version 7.3 of the Android Gradle Plugin (AGP) uses a version of R8 that contains a bug which causes this error (see more info at https://issuetracker.google.com/issues/242308990).
665+
To fix this error, update to a newer version of AGP (at least 7.4.0).
666+
667+
${_getAgpLocation(project)}''',
668+
title: _boxTitle,
669+
);
670+
671+
return GradleBuildStatus.exit;
672+
},
673+
eventLabel: 'r8-dexing-bug-in-AGP-7.3'
674+
);

packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -426,61 +426,6 @@ void main() {
426426
AndroidStudio: () => FakeAndroidStudio(),
427427
});
428428

429-
testUsingContext('guides the user when the shrinker fails', () async {
430-
final String projectPath = await createProject(tempDir, arguments: <String>['--no-pub', '--template=app', '--platform=android']);
431-
const String r8StdoutWarning =
432-
"Execution failed for task ':app:transformClassesAndResourcesWithR8ForStageInternal'.\n"
433-
'> com.android.tools.r8.CompilationFailedException: Compilation failed to complete';
434-
processManager.addCommand(FakeCommand(
435-
command: <String>[
436-
gradlew,
437-
'-q',
438-
'-Ptarget-platform=android-arm,android-arm64,android-x64',
439-
'-Ptarget=${globals.fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
440-
'-Pbase-application-name=android.app.Application',
441-
'-Pdart-obfuscation=false',
442-
'-Ptrack-widget-creation=true',
443-
'-Ptree-shake-icons=true',
444-
'assembleRelease',
445-
],
446-
exitCode: 1,
447-
stdout: r8StdoutWarning,
448-
));
449-
450-
await expectLater(
451-
() => runBuildApkCommand(
452-
projectPath,
453-
),
454-
throwsToolExit(message: 'Gradle task assembleRelease failed with exit code 1'),
455-
);
456-
expect(
457-
testLogger.statusText, allOf(
458-
containsIgnoringWhitespace('The shrinker may have failed to optimize the Java bytecode.'),
459-
containsIgnoringWhitespace('To disable the shrinker, pass the `--no-shrink` flag to this command.'),
460-
containsIgnoringWhitespace('To learn more, see: https://developer.android.com/studio/build/shrink-code'),
461-
)
462-
);
463-
464-
expect(
465-
analytics.sentEvents,
466-
contains(
467-
Event.flutterBuildInfo(
468-
label: 'gradle-r8-failure',
469-
buildType: 'gradle',
470-
),
471-
),
472-
);
473-
expect(processManager, hasNoRemainingExpectations);
474-
},
475-
overrides: <Type, Generator>{
476-
AndroidSdk: () => mockAndroidSdk,
477-
Java: () => null,
478-
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
479-
ProcessManager: () => processManager,
480-
Analytics: () => analytics,
481-
AndroidStudio: () => FakeAndroidStudio(),
482-
});
483-
484429
testUsingContext("reports when the app isn't using AndroidX", () async {
485430
final String projectPath = await createProject(tempDir, arguments: <String>['--no-pub', '--template=app', '--platform=android']);
486431
// Simulate a non-androidx project.

packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,10 @@ void main() {
3838
networkErrorHandler,
3939
permissionDeniedErrorHandler,
4040
flavorUndefinedHandler,
41-
r8FailureHandler,
41+
r8DexingBugInAgp73Handler,
4242
minSdkVersionHandler,
4343
transformInputIssueHandler,
4444
lockFileDepMissingHandler,
45-
incompatibleKotlinVersionHandler,
4645
minCompileSdkVersionHandler,
4746
jvm11RequiredHandler,
4847
outdatedGradleHandler,
@@ -52,6 +51,7 @@ void main() {
5251
remoteTerminatedHandshakeHandler,
5352
couldNotOpenCacheDirectoryHandler,
5453
incompatibleCompileSdk35AndAgpVersionHandler,
54+
incompatibleKotlinVersionHandler,
5555
])
5656
);
5757
});
@@ -1320,7 +1320,6 @@ Execution failed for task ':app:bundleReleaseResources'.
13201320
'│ /android/settings.gradle, │\n'
13211321
"│ in the 'plugins' closure. │\n"
13221322
'│ Alternatively, if your project was created with an older version of the templates, it is likely │\n'
1323-
'│ │\n'
13241323
'│ in the buildscript.dependencies closure of the top-level build.gradle: │\n'
13251324
'│ /android/build.gradle. │\n'
13261325
'│ │\n'
@@ -1337,6 +1336,43 @@ Execution failed for task ':app:bundleReleaseResources'.
13371336
FileSystem: () => fileSystem,
13381337
ProcessManager: () => processManager,
13391338
});
1339+
1340+
testUsingContext('AGP 7.3.0 R8 bug', () async {
1341+
const String errorExample = r'''
1342+
ERROR:/Users/mackall/.gradle/caches/transforms-3/bd2c84591857c6d4c308221ffece862e/transformed/jetified-media3-exoplayer-dash-1.4.0-runtime.jar: R8: com.android.tools.r8.internal.Y10: Unused argument with users in androidx
1343+
''';
1344+
1345+
await r8DexingBugInAgp73Handler.handler(
1346+
line: errorExample,
1347+
project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
1348+
usesAndroidX: true,
1349+
);
1350+
1351+
expect(
1352+
testLogger.statusText,
1353+
contains(
1354+
'\n'
1355+
'┌─ Flutter Fix ────────────────────────────────────────────────────────────────────────────────────┐\n'
1356+
'│ [!] Version 7.3 of the Android Gradle Plugin (AGP) uses a version of R8 that contains a bug │\n'
1357+
'│ which causes this error (see more info at https://issuetracker.google.com/issues/242308990). │\n'
1358+
'│ To fix this error, update to a newer version of AGP (at least 7.4.0). │\n'
1359+
'│ │\n'
1360+
'│ The version of AGP that your project uses is likely defined in: │\n'
1361+
'│ /android/settings.gradle, │\n'
1362+
"│ in the 'plugins' closure. │\n"
1363+
'│ Alternatively, if your project was created with an older version of the templates, it is likely │\n'
1364+
'│ in the buildscript.dependencies closure of the top-level build.gradle: │\n'
1365+
'│ /android/build.gradle. │\n'
1366+
'└──────────────────────────────────────────────────────────────────────────────────────────────────┘\n'
1367+
''
1368+
)
1369+
);
1370+
}, overrides: <Type, Generator>{
1371+
GradleUtils: () => FakeGradleUtils(),
1372+
Platform: () => fakePlatform('android'),
1373+
FileSystem: () => fileSystem,
1374+
ProcessManager: () => processManager,
1375+
});
13401376
}
13411377

13421378
bool formatTestErrorMessage(String errorMessage, GradleHandledError error) {

0 commit comments

Comments
 (0)