From 33be93b210839a38cf87a59eb1c2024804a8cc98 Mon Sep 17 00:00:00 2001 From: John McDole Date: Mon, 1 Jul 2024 11:50:24 -0700 Subject: [PATCH] Read AndroidManifest.xml and emit manifest-aar-impeller-(enabled|disabled) analytics (#150970) Same as #150791 except with AARs (`flutter build module`) --- .../lib/src/commands/build_aar.dart | 14 ++ .../permeable/build_aar_test.dart | 125 ++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/packages/flutter_tools/lib/src/commands/build_aar.dart b/packages/flutter_tools/lib/src/commands/build_aar.dart index 10a324b609..536d8fce1e 100644 --- a/packages/flutter_tools/lib/src/commands/build_aar.dart +++ b/packages/flutter_tools/lib/src/commands/build_aar.dart @@ -12,6 +12,7 @@ import '../base/file_system.dart'; import '../base/os.dart'; import '../build_info.dart'; import '../cache.dart'; +import '../globals.dart' as globals; import '../project.dart'; import '../reporting/reporting.dart'; import '../runner/flutter_command.dart' show FlutterCommandResult; @@ -174,6 +175,19 @@ class BuildAarCommand extends BuildSubCommand { outputDirectoryPath: stringArg('output'), buildNumber: buildNumber, ); + + // When an aar is successfully built, record to analytics whether Impeller + // is enabled or disabled. Note that 'computeImpellerEnabled' will default + // to false if not enabled explicitly in the manifest. + final bool impellerEnabled = project.android.computeImpellerEnabled(); + final String buildLabel = impellerEnabled + ? 'manifest-aar-impeller-enabled' + : 'manifest-aar-impeller-disabled'; + globals.analytics.send(Event.flutterBuildInfo( + label: buildLabel, + buildType: 'android', + )); + return FlutterCommandResult.success(); } diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart index b2e41ed09a..714164bedc 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:args/command_runner.dart'; +import 'package:file/memory.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/android_studio.dart'; @@ -17,6 +18,7 @@ import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:test/fake.dart'; +import 'package:unified_analytics/unified_analytics.dart'; import '../../src/android_common.dart'; import '../../src/common.dart'; @@ -191,9 +193,14 @@ void main() { late String gradlew; late FakeProcessManager processManager; late String flutterRoot; + late FakeAnalytics fakeAnalytics; setUp(() { tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); + fakeAnalytics = getInitializedFakeAnalyticsInstance( + fs: MemoryFileSystem.test(), + fakeFlutterVersion: FakeFlutterVersion(), + ); mockAndroidSdk = FakeAndroidSdk(); gradlew = globals.fs.path.join(tempDir.path, 'flutter_project', '.android', globals.platform.isWindows ? 'gradlew.bat' : 'gradlew'); @@ -290,6 +297,124 @@ void main() { FeatureFlags: () => TestFeatureFlags(isIOSEnabled: false), AndroidStudio: () => FakeAndroidStudio(), }); + + group('Impeller AndroidManifest.xml setting', () { + // Adds a key-value `` pair to the `` tag in the + // cooresponding `AndroidManifest.xml` file, right before the closing + // `` tag. + void writeManifestMetadata({ + required String projectPath, + required String name, + required String value, + }) { + final String manifestPath = globals.fs.path.join( + projectPath, + '.android', + 'app', + 'src', + 'main', + 'AndroidManifest.xml', + ); + + // It would be unnecessarily complicated to parse this XML file and + // insert the key-value pair, so we just insert it right before the + // closing tag. + final String oldManifest = globals.fs.file(manifestPath).readAsStringSync(); + final String newManifest = oldManifest.replaceFirst( + '', + ' \n' + ' ', + ); + globals.fs.file(manifestPath).writeAsStringSync(newManifest); + } + + testUsingContext('a default AAR build reports Impeller as disabled', () async { + final String projectPath = await createProject( + tempDir, + arguments: ['--no-pub', '--template=module'] + ); + + await runBuildAarCommand(projectPath, mockAndroidSdk); + + expect( + fakeAnalytics.sentEvents, + contains( + Event.flutterBuildInfo( + label: 'manifest-aar-impeller-disabled', + buildType: 'android', + ), + ), + ); + }, overrides: { + Analytics: () => fakeAnalytics, + AndroidBuilder: () => FakeAndroidBuilder(), + FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), + }); + + testUsingContext('EnableImpeller="true" reports an enabled event', () async { + final String projectPath = await createProject( + tempDir, + arguments: ['--no-pub', '--template=module'] + ); + final FlutterProject project = FlutterProject.fromDirectory(globals.fs.directory(projectPath)); + await project.android.ensureReadyForPlatformSpecificTooling(); + + writeManifestMetadata( + projectPath: projectPath, + name: 'io.flutter.embedding.android.EnableImpeller', + value: 'true', + ); + + await runBuildAarCommand(projectPath, mockAndroidSdk); + + expect( + fakeAnalytics.sentEvents, + contains( + Event.flutterBuildInfo( + label: 'manifest-aar-impeller-enabled', + buildType: 'android', + ), + ), + ); + }, overrides: { + Analytics: () => fakeAnalytics, + AndroidBuilder: () => FakeAndroidBuilder(), + FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), + }); + + testUsingContext('EnableImpeller="false" reports an disabled event', () async { + final String projectPath = await createProject( + tempDir, + arguments: ['--no-pub', '--template=module'] + ); + final FlutterProject project = FlutterProject.fromDirectory(globals.fs.directory(projectPath)); + await project.android.ensureReadyForPlatformSpecificTooling(); + + writeManifestMetadata( + projectPath: projectPath, + name: 'io.flutter.embedding.android.EnableImpeller', + value: 'false', + ); + + await runBuildAarCommand(projectPath, mockAndroidSdk); + + expect( + fakeAnalytics.sentEvents, + contains( + Event.flutterBuildInfo( + label: 'manifest-aar-impeller-disabled', + buildType: 'android', + ), + ), + ); + }, overrides: { + Analytics: () => fakeAnalytics, + AndroidBuilder: () => FakeAndroidBuilder(), + FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), + }); + }); }); }