Enable R8 (#40453)
diff --git a/packages/flutter_tools/test/general.shard/android/gradle_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_test.dart
index e583a46..b650ab0 100644
--- a/packages/flutter_tools/test/general.shard/android/gradle_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/gradle_test.dart
@@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'dart:async';
-import 'dart:io';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_sdk.dart';
@@ -13,6 +12,7 @@
import 'package:flutter_tools/src/artifacts.dart';
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';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
@@ -867,6 +867,13 @@
gradleWrapperDirectory
.childFile(gradleBinary)
.writeAsStringSync('irrelevant');
+ fs.currentDirectory
+ .childDirectory('android')
+ .createSync();
+ fs.currentDirectory
+ .childDirectory('android')
+ .childFile('gradle.properties')
+ .writeAsStringSync('irrelevant');
gradleWrapperDirectory
.childDirectory('gradle')
.childDirectory('wrapper')
@@ -1072,6 +1079,82 @@
});
});
+ group('migrateToR8', () {
+ MemoryFileSystem memoryFileSystem;
+
+ setUp(() {
+ memoryFileSystem = MemoryFileSystem();
+ });
+
+ testUsingContext('throws ToolExit if gradle.properties doesn\'t exist', () {
+ final Directory sampleAppAndroid = fs.directory('/sample-app/android');
+ sampleAppAndroid.createSync(recursive: true);
+
+ expect(() {
+ migrateToR8(sampleAppAndroid);
+ }, throwsToolExit(message: 'Expected file ${sampleAppAndroid.path}'));
+
+ }, overrides: <Type, Generator>{
+ FileSystem: () => memoryFileSystem,
+ });
+
+ testUsingContext('throws ToolExit if it cannot write gradle.properties', () {
+ final MockDirectory sampleAppAndroid = MockDirectory();
+ final MockFile gradleProperties = MockFile();
+
+ when(gradleProperties.path).thenReturn('foo/gradle.properties');
+ when(gradleProperties.existsSync()).thenReturn(true);
+ when(gradleProperties.readAsStringSync()).thenReturn('');
+ when(gradleProperties.writeAsStringSync('android.enableR8=true\n', mode: FileMode.append))
+ .thenThrow(const FileSystemException());
+
+ when(sampleAppAndroid.childFile('gradle.properties'))
+ .thenReturn(gradleProperties);
+
+ expect(() {
+ migrateToR8(sampleAppAndroid);
+ },
+ throwsToolExit(message:
+ 'The tool failed to add `android.enableR8=true` to foo/gradle.properties. '
+ 'Please update the file manually and try this command again.'));
+ });
+
+ testUsingContext('does not update gradle.properties if it already uses R8', () {
+ final Directory sampleAppAndroid = fs.directory('/sample-app/android');
+ sampleAppAndroid.createSync(recursive: true);
+ sampleAppAndroid.childFile('gradle.properties')
+ .writeAsStringSync('android.enableR8=true');
+
+ migrateToR8(sampleAppAndroid);
+
+ expect(testLogger.traceText,
+ contains('gradle.properties already sets `android.enableR8`'));
+ expect(sampleAppAndroid.childFile('gradle.properties').readAsStringSync(),
+ equals('android.enableR8=true'));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => memoryFileSystem,
+ });
+
+ testUsingContext('sets android.enableR8=true', () {
+ final Directory sampleAppAndroid = fs.directory('/sample-app/android');
+ sampleAppAndroid.createSync(recursive: true);
+ sampleAppAndroid.childFile('gradle.properties')
+ .writeAsStringSync('org.gradle.jvmargs=-Xmx1536M\n');
+
+ migrateToR8(sampleAppAndroid);
+
+ expect(testLogger.traceText, contains('set `android.enableR8=true` in gradle.properties'));
+ expect(sampleAppAndroid.childFile('gradle.properties').readAsStringSync(),
+ equals(
+ 'org.gradle.jvmargs=-Xmx1536M\n'
+ 'android.enableR8=true\n'
+ )
+ );
+ }, overrides: <Type, Generator>{
+ FileSystem: () => memoryFileSystem,
+ });
+ });
+
group('gradle build', () {
MockAndroidSdk mockAndroidSdk;
MockAndroidStudio mockAndroidStudio;
@@ -1136,6 +1219,9 @@
final File gradlew = fs.file('path/to/project/.android/gradlew');
gradlew.createSync(recursive: true);
+ fs.file('path/to/project/.android/gradle.properties')
+ .writeAsStringSync('irrelevant');
+
when(mockProcessManager.run(
<String> ['/path/to/project/.android/gradlew', '-v'],
workingDirectory: anyNamed('workingDirectory'),
@@ -1198,9 +1284,11 @@
return FakePlatform.fromPlatform(const LocalPlatform())..operatingSystem = name;
}
+class MockAndroidStudio extends Mock implements AndroidStudio {}
+class MockDirectory extends Mock implements Directory {}
+class MockFile extends Mock implements File {}
+class MockGradleProject extends Mock implements GradleProject {}
class MockLocalEngineArtifacts extends Mock implements LocalEngineArtifacts {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterpreter {}
-class MockGradleProject extends Mock implements GradleProject {}
class MockitoAndroidSdk extends Mock implements AndroidSdk {}
-class MockAndroidStudio extends Mock implements AndroidStudio {}
diff --git a/packages/flutter_tools/test/general.shard/application_package_test.dart b/packages/flutter_tools/test/general.shard/application_package_test.dart
index a374142..05855b0 100644
--- a/packages/flutter_tools/test/general.shard/application_package_test.dart
+++ b/packages/flutter_tools/test/general.shard/application_package_test.dart
@@ -103,6 +103,10 @@
platform.isWindows ? 'gradlew.bat' : 'gradlew',
)..createSync(recursive: true);
+ project.android.hostAppGradleRoot
+ .childFile('gradle.properties')
+ .writeAsStringSync('irrelevant');
+
final Directory gradleWrapperDir = fs.systemTempDirectory.createTempSync('gradle_wrapper.');
when(mockCache.getArtifactDirectory('gradle_wrapper')).thenReturn(gradleWrapperDir);
diff --git a/packages/flutter_tools/test/general.shard/commands/build_apk_test.dart b/packages/flutter_tools/test/general.shard/commands/build_apk_test.dart
index f3d19b8..1c961ad 100644
--- a/packages/flutter_tools/test/general.shard/commands/build_apk_test.dart
+++ b/packages/flutter_tools/test/general.shard/commands/build_apk_test.dart
@@ -137,7 +137,7 @@
tryToDelete(tempDir);
});
- testUsingContext('proguard is enabled by default on release mode', () async {
+ testUsingContext('shrinking is enabled by default on release mode', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
@@ -151,7 +151,7 @@
'-q',
'-Ptarget=${fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Ptrack-widget-creation=false',
- '-Pproguard=true',
+ '-Pshrink=true',
'-Ptarget-platform=android-arm,android-arm64',
'assembleRelease',
],
@@ -165,17 +165,16 @@
GradleUtils: () => GradleUtils(),
ProcessManager: () => mockProcessManager,
},
- skip: true,
timeout: allowForCreateFlutterProject);
- testUsingContext('proguard is disabled when --no-proguard is passed', () async {
+ testUsingContext('shrinking is disabled when --no-shrink 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'],
+ arguments: <String>['--no-shrink'],
);
}, throwsToolExit(message: 'Gradle task assembleRelease failed with exit code 1'));
@@ -198,10 +197,9 @@
GradleUtils: () => GradleUtils(),
ProcessManager: () => mockProcessManager,
},
- skip: true,
timeout: allowForCreateFlutterProject);
- testUsingContext('guides the user when proguard fails', () async {
+ testUsingContext('guides the user when the shrinker fails', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
@@ -211,22 +209,20 @@
'-q',
'-Ptarget=${fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Ptrack-widget-creation=false',
- '-Pproguard=true',
+ '-Pshrink=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)';
+ const String r8StdoutWarning =
+ 'Execution failed for task \':app:transformClassesAndResourcesWithR8ForStageInternal\'.'
+ '> com.android.tools.r8.CompilationFailedException: Compilation failed to complete';
return Future<Process>.value(
createMockProcess(
exitCode: 1,
- stdout: proguardStdoutWarning,
+ stdout: r8StdoutWarning,
)
);
});
@@ -238,15 +234,15 @@
}, throwsToolExit(message: 'Gradle task assembleRelease failed with exit code 1'));
expect(testLogger.statusText,
- contains('Proguard may have failed to optimize the Java bytecode.'));
+ contains('The shrinker may have failed to optimize the Java bytecode.'));
expect(testLogger.statusText,
- contains('To disable proguard, pass the `--no-proguard` flag to this command.'));
+ contains('To disable the shrinker, pass the `--no-shrink` flag to this command.'));
expect(testLogger.statusText,
- contains('To learn more about Proguard, see: https://flutter.dev/docs/deployment/android#enabling-proguard'));
+ contains('To learn more, see: https://developer.android.com/studio/build/shrink-code'));
verify(mockUsage.sendEvent(
'build-apk',
- 'proguard-failure',
+ 'r8-failure',
parameters: anyNamed('parameters'),
)).called(1);
},
@@ -257,7 +253,6 @@
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
},
- skip: true,
timeout: allowForCreateFlutterProject);
});
}
diff --git a/packages/flutter_tools/test/general.shard/commands/build_appbundle_test.dart b/packages/flutter_tools/test/general.shard/commands/build_appbundle_test.dart
index 4548e3c..4a7d98f 100644
--- a/packages/flutter_tools/test/general.shard/commands/build_appbundle_test.dart
+++ b/packages/flutter_tools/test/general.shard/commands/build_appbundle_test.dart
@@ -75,7 +75,7 @@
}, timeout: allowForCreateFlutterProject);
});
- group('Flags', () {
+ group('Gradle', () {
Directory tempDir;
ProcessManager mockProcessManager;
MockAndroidSdk mockAndroidSdk;
@@ -122,7 +122,7 @@
tryToDelete(tempDir);
});
- testUsingContext('proguard is enabled by default on release mode', () async {
+ testUsingContext('shrinking is enabled by default on release mode', () async {
final String projectPath = await createProject(
tempDir,
arguments: <String>['--no-pub', '--template=app'],
@@ -138,7 +138,7 @@
'-q',
'-Ptarget=${fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Ptrack-widget-creation=false',
- '-Pproguard=true',
+ '-Pshrink=true',
'-Ptarget-platform=android-arm,android-arm64',
'bundleRelease',
],
@@ -152,10 +152,9 @@
GradleUtils: () => GradleUtils(),
ProcessManager: () => mockProcessManager,
},
- skip: true,
timeout: allowForCreateFlutterProject);
- testUsingContext('proguard is disabled when --no-proguard is passed', () async {
+ testUsingContext('shrinking is disabled when --no-shrink is passed', () async {
final String projectPath = await createProject(
tempDir,
arguments: <String>['--no-pub', '--template=app'],
@@ -164,7 +163,7 @@
await expectLater(() async {
await runBuildAppBundleCommand(
projectPath,
- arguments: <String>['--no-proguard'],
+ arguments: <String>['--no-shrink'],
);
}, throwsToolExit(message: 'Gradle task bundleRelease failed with exit code 1'));
@@ -187,10 +186,9 @@
GradleUtils: () => GradleUtils(),
ProcessManager: () => mockProcessManager,
},
- skip: true,
timeout: allowForCreateFlutterProject);
- testUsingContext('guides the user when proguard fails', () async {
+ testUsingContext('guides the user when the shrinker fails', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
@@ -200,22 +198,20 @@
'-q',
'-Ptarget=${fs.path.join(tempDir.path, 'flutter_project', 'lib', 'main.dart')}',
'-Ptrack-widget-creation=false',
- '-Pproguard=true',
+ '-Pshrink=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)';
+ const String r8StdoutWarning =
+ 'Execution failed for task \':app:transformClassesAndResourcesWithR8ForStageInternal\'.'
+ '> com.android.tools.r8.CompilationFailedException: Compilation failed to complete';
return Future<Process>.value(
createMockProcess(
exitCode: 1,
- stdout: proguardStdoutWarning,
+ stdout: r8StdoutWarning,
)
);
});
@@ -227,15 +223,15 @@
}, throwsToolExit(message: 'Gradle task bundleRelease failed with exit code 1'));
expect(testLogger.statusText,
- contains('Proguard may have failed to optimize the Java bytecode.'));
+ contains('The shrinker may have failed to optimize the Java bytecode.'));
expect(testLogger.statusText,
- contains('To disable proguard, pass the `--no-proguard` flag to this command.'));
+ contains('To disable the shrinker, pass the `--no-shrink` flag to this command.'));
expect(testLogger.statusText,
- contains('To learn more about Proguard, see: https://flutter.dev/docs/deployment/android#enabling-proguard'));
+ contains('To learn more, see: https://developer.android.com/studio/build/shrink-code'));
verify(mockUsage.sendEvent(
'build-appbundle',
- 'proguard-failure',
+ 'r8-failure',
parameters: anyNamed('parameters'),
)).called(1);
},
@@ -246,7 +242,6 @@
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
},
- skip: true,
timeout: allowForCreateFlutterProject);
});
}