From d8a5f3d11bd4216c63766febe0cfb15bf79f44af Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Thu, 16 Nov 2023 14:59:02 -0800 Subject: [PATCH] Improves output file path logic in Android analyze (#136981) --- .../gradle/src/main/groovy/flutter.groovy | 4 ++-- .../lib/src/android/android_builder.dart | 4 +++- packages/flutter_tools/lib/src/android/gradle.dart | 12 ++++++++++-- .../lib/src/commands/android_analyze.dart | 3 +-- packages/flutter_tools/lib/src/project.dart | 11 ++++++----- .../hermetic/android_analyze_test.dart | 5 ++++- .../android/android_gradle_builder_test.dart | 9 +++++++-- ...ndroid_gradle_outputs_app_link_settings_test.dart | 8 ++++---- packages/flutter_tools/test/src/android_common.dart | 5 ++--- 9 files changed, 39 insertions(+), 22 deletions(-) diff --git a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy index 0e0998069c0..f7b0d372b55 100644 --- a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy +++ b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy @@ -752,7 +752,7 @@ class FlutterPlugin implements Plugin { // // See https://developer.android.com/training/app-links/ for more information about app link. // - // The json will be stored in /build/app/app-link-settings-.json + // The json will be saved in path stored in outputPath parameter. // // An example json: // { @@ -830,7 +830,7 @@ class FlutterPlugin implements Plugin { } } def generator = new JsonGenerator.Options().build() - new File(project.buildDir, "app-link-settings-${variant.name}.json").write(generator.toJson(appLinkSettings)) + new File(project.getProperty("outputPath")).write(generator.toJson(appLinkSettings)) } } } diff --git a/packages/flutter_tools/lib/src/android/android_builder.dart b/packages/flutter_tools/lib/src/android/android_builder.dart index 0ece6ceaaf0..f50bfb0b3d3 100644 --- a/packages/flutter_tools/lib/src/android/android_builder.dart +++ b/packages/flutter_tools/lib/src/android/android_builder.dart @@ -44,7 +44,9 @@ abstract class AndroidBuilder { Future> getBuildVariants({required FlutterProject project}); /// Outputs app link related project settings into a json file. - Future outputsAppLinkSettings( + /// + /// The return future resolves to the path of the json file. + Future outputsAppLinkSettings( String buildVariant, { required FlutterProject project, }); diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart index 2e63b8f285b..1a54700be43 100644 --- a/packages/flutter_tools/lib/src/android/gradle.dart +++ b/packages/flutter_tools/lib/src/android/gradle.dart @@ -810,16 +810,22 @@ class AndroidGradleBuilder implements AndroidBuilder { } @override - Future outputsAppLinkSettings( + Future outputsAppLinkSettings( String buildVariant, { required FlutterProject project, }) async { final String taskName = _getOutputAppLinkSettingsTaskFor(buildVariant); + final Directory directory = await project.buildDirectory + .childDirectory('deeplink_data').create(recursive: true); + final String outputPath = globals.fs.path.join( + directory.absolute.path, + 'app-link-settings-$buildVariant.json', + ); final Stopwatch sw = Stopwatch() ..start(); final RunResult result = await _runGradleTask( taskName, - options: const ['-q'], + options: ['-q', '-PoutputPath=$outputPath'], project: project, ); _usage.sendTiming('outputs', 'app link settings', sw.elapsed); @@ -827,7 +833,9 @@ class AndroidGradleBuilder implements AndroidBuilder { if (result.exitCode != 0) { _logger.printStatus(result.stdout, wrap: false); _logger.printError(result.stderr, wrap: false); + throwToolExit(result.stderr); } + return outputPath; } } diff --git a/packages/flutter_tools/lib/src/commands/android_analyze.dart b/packages/flutter_tools/lib/src/commands/android_analyze.dart index c4389ff41e1..9d6af0b9905 100644 --- a/packages/flutter_tools/lib/src/commands/android_analyze.dart +++ b/packages/flutter_tools/lib/src/commands/android_analyze.dart @@ -48,8 +48,7 @@ class AndroidAnalyze { logger.printStatus(jsonEncode(await project.android.getBuildVariants())); case AndroidAnalyzeOption.outputAppLinkSettings: assert(buildVariant != null); - await project.android.outputsAppLinkSettings(variant: buildVariant!); - final String filePath = fileSystem.path.join(project.directory.path, 'build', 'app', 'app-link-settings-$buildVariant.json`'); + final String filePath = await project.android.outputsAppLinkSettings(variant: buildVariant!); logger.printStatus('result saved in $filePath'); } } diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 07c57a15b65..93ca512363b 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -501,13 +501,14 @@ class AndroidProject extends FlutterProjectPlatform { /// Outputs app link related settings into a json file. /// - /// The file is stored in - /// `/build/app/app-link-settings-.json`. - Future outputsAppLinkSettings({required String variant}) async { + /// The return future resolves to the path of the json file. + /// + /// The future resolves to null if it fails to retrieve app link settings. + Future outputsAppLinkSettings({required String variant}) async { if (!existsSync() || androidBuilder == null) { - return; + throwToolExit('Target directory $hostAppGradleRoot is not an Android project'); } - await androidBuilder!.outputsAppLinkSettings(variant, project: parent); + return androidBuilder!.outputsAppLinkSettings(variant, project: parent); } bool _computeSupportedVersion() { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/android_analyze_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/android_analyze_test.dart index 44c9c5fa34c..07e5a34e97e 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/android_analyze_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/android_analyze_test.dart @@ -94,6 +94,7 @@ void main() { const String buildVariant = 'release'; await runner.run(['analyze', '--android', '--output-app-link-settings', '--build-variant=$buildVariant', tempDir.path]); expect(builder.outputVariant, buildVariant); + expect(logger.statusText, contains(builder.outputPath)); }, overrides: { AndroidBuilder: () => builder, }); @@ -116,6 +117,7 @@ void main() { class FakeAndroidBuilder extends Fake implements AndroidBuilder { List variants = const []; String? outputVariant; + final String outputPath = '/'; @override Future> getBuildVariants({required FlutterProject project}) async { @@ -123,7 +125,8 @@ class FakeAndroidBuilder extends Fake implements AndroidBuilder { } @override - Future outputsAppLinkSettings(String buildVariant, {required FlutterProject project}) async { + Future outputsAppLinkSettings(String buildVariant, {required FlutterProject project}) async { outputVariant = buildVariant; + return outputPath; } } diff --git a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart index 35771e027c1..95a1fd6c3e7 100644 --- a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart @@ -914,7 +914,9 @@ Gradle Crashed AndroidStudio: () => FakeAndroidStudio(), }); - testUsingContext('can call custom gradle task getApplicationIdForVariant and parse the result', () async { + testUsingContext('can call custom gradle task outputFreeDebugAppLinkSettings and parse the result', () async { + final String expectedOutputPath; + expectedOutputPath = fileSystem.path.join('/build/deeplink_data', 'app-link-settings-freeDebug.json'); final AndroidGradleBuilder builder = AndroidGradleBuilder( java: FakeJava(), logger: logger, @@ -927,10 +929,11 @@ Gradle Crashed platform: FakePlatform(), androidStudio: FakeAndroidStudio(), ); - processManager.addCommand(const FakeCommand( + processManager.addCommand(FakeCommand( command: [ 'gradlew', '-q', + '-PoutputPath=$expectedOutputPath', 'outputFreeDebugAppLinkSettings', ], )); @@ -940,6 +943,8 @@ Gradle Crashed ); }, overrides: { AndroidStudio: () => FakeAndroidStudio(), + FileSystem: () => fileSystem, + ProcessManager: () => processManager, }); testUsingContext("doesn't indicate how to consume an AAR when printHowToConsumeAar is false", () async { diff --git a/packages/flutter_tools/test/integration.shard/android_gradle_outputs_app_link_settings_test.dart b/packages/flutter_tools/test/integration.shard/android_gradle_outputs_app_link_settings_test.dart index 7a1bf43babe..0d42ddbd94f 100644 --- a/packages/flutter_tools/test/integration.shard/android_gradle_outputs_app_link_settings_test.dart +++ b/packages/flutter_tools/test/integration.shard/android_gradle_outputs_app_link_settings_test.dart @@ -175,16 +175,16 @@ void main() { expect(result, const ProcessResultMatcher()); final Directory androidApp = tempDir.childDirectory('android'); + final io.File fileDump = tempDir.childDirectory('build').childDirectory('app').childFile('app-link-settings-debug.json'); result = await processManager.run([ '.${platform.pathSeparator}${getGradlewFileName(platform)}', ...getLocalEngineArguments(), '-q', // quiet output. + '-PoutputPath=${fileDump.path}', 'outputDebugAppLinkSettings', ], workingDirectory: androidApp.path); expect(result, const ProcessResultMatcher()); - - final io.File fileDump = tempDir.childDirectory('build').childDirectory('app').childFile('app-link-settings-debug.json'); expect(fileDump.existsSync(), true); final Map json = jsonDecode(fileDump.readAsStringSync()) as Map; expect(json['applicationId'], 'com.example.testapp'); @@ -220,16 +220,16 @@ void main() { expect(result, const ProcessResultMatcher()); final Directory androidApp = tempDir.childDirectory('android'); + final io.File fileDump = tempDir.childDirectory('build').childDirectory('app').childFile('app-link-settings-debug.json'); result = await processManager.run([ '.${platform.pathSeparator}${getGradlewFileName(platform)}', ...getLocalEngineArguments(), '-q', // quiet output. + '-PoutputPath=${fileDump.path}', 'outputDebugAppLinkSettings', ], workingDirectory: androidApp.path); expect(result, const ProcessResultMatcher()); - - final io.File fileDump = tempDir.childDirectory('build').childDirectory('app').childFile('app-link-settings-debug.json'); expect(fileDump.existsSync(), true); final Map json = jsonDecode(fileDump.readAsStringSync()) as Map; expect(json['applicationId'], 'com.example.testapp'); diff --git a/packages/flutter_tools/test/src/android_common.dart b/packages/flutter_tools/test/src/android_common.dart index 2b1624d6a9b..d8f531a4fa8 100644 --- a/packages/flutter_tools/test/src/android_common.dart +++ b/packages/flutter_tools/test/src/android_common.dart @@ -41,11 +41,10 @@ class FakeAndroidBuilder implements AndroidBuilder { Future> getBuildVariants({required FlutterProject project}) async => const []; @override - Future outputsAppLinkSettings( + Future outputsAppLinkSettings( String buildVariant, { required FlutterProject project, - }) async {} - + }) async => '/'; } /// Creates a [FlutterProject] in a directory named [flutter_project]