Show a warning when a module uses a v1 only plugin (#44499)
diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart index ea41d4d..802d8034 100644 --- a/packages/flutter_tools/test/general.shard/plugins_test.dart +++ b/packages/flutter_tools/test/general.shard/plugins_test.dart
@@ -55,7 +55,7 @@ dummyPackageDirectory = fs.directory('/pubcache/apackage/lib/'); packagesFile = fs.file(fs.path.join(flutterProject.directory.path, PackageMap.globalPackagesPath)); packagesFile..createSync(recursive: true) - ..writeAsStringSync('apackage:file://${dummyPackageDirectory.path}'); + ..writeAsStringSync('apackage:file://${dummyPackageDirectory.path}\n'); }); // Makes the dummy package pointed to by packagesFile look like a plugin. @@ -69,6 +69,126 @@ '''); } + + void createNewJavaPlugin1() { + final Directory pluginUsingJavaAndNewEmbeddingDir = + fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.'); + pluginUsingJavaAndNewEmbeddingDir + .childFile('pubspec.yaml') + .writeAsStringSync(''' +flutter: + plugin: + androidPackage: plugin1 + pluginClass: UseNewEmbedding + '''); + pluginUsingJavaAndNewEmbeddingDir + .childDirectory('android') + .childDirectory('src') + .childDirectory('main') + .childDirectory('java') + .childDirectory('plugin1') + .childFile('UseNewEmbedding.java') + ..createSync(recursive: true) + ..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin;'); + + flutterProject.directory + .childFile('.packages') + .writeAsStringSync( + 'plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()}\n', + mode: FileMode.append, + ); + } + + void createNewKotlinPlugin2() { + final Directory pluginUsingKotlinAndNewEmbeddingDir = + fs.systemTempDirectory.createTempSync('flutter_plugin_using_kotlin_and_new_embedding_dir.'); + pluginUsingKotlinAndNewEmbeddingDir + .childFile('pubspec.yaml') + .writeAsStringSync(''' +flutter: + plugin: + androidPackage: plugin2 + pluginClass: UseNewEmbedding + '''); + pluginUsingKotlinAndNewEmbeddingDir + .childDirectory('android') + .childDirectory('src') + .childDirectory('main') + .childDirectory('kotlin') + .childDirectory('plugin2') + .childFile('UseNewEmbedding.kt') + ..createSync(recursive: true) + ..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin'); + + flutterProject.directory + .childFile('.packages') + .writeAsStringSync( + 'plugin2:${pluginUsingKotlinAndNewEmbeddingDir.childDirectory('lib').uri.toString()}\n', + mode: FileMode.append, + ); + } + + void createOldJavaPlugin3() { + final Directory pluginUsingOldEmbeddingDir = + fs.systemTempDirectory.createTempSync('flutter_plugin_using_old_embedding_dir.'); + pluginUsingOldEmbeddingDir + .childFile('pubspec.yaml') + .writeAsStringSync(''' +flutter: + plugin: + androidPackage: plugin3 + pluginClass: UseOldEmbedding + '''); + pluginUsingOldEmbeddingDir + .childDirectory('android') + .childDirectory('src') + .childDirectory('main') + .childDirectory('java') + .childDirectory('plugin3') + .childFile('UseOldEmbedding.java') + ..createSync(recursive: true); + + flutterProject.directory + .childFile('.packages') + .writeAsStringSync( + 'plugin3:${pluginUsingOldEmbeddingDir.childDirectory('lib').uri.toString()}\n', + mode: FileMode.append, + ); + } + + void createDualSupportJavaPlugin4() { + final Directory pluginUsingJavaAndNewEmbeddingDir = + fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.'); + pluginUsingJavaAndNewEmbeddingDir + .childFile('pubspec.yaml') + .writeAsStringSync(''' +flutter: + plugin: + androidPackage: plugin4 + pluginClass: UseBothEmbedding +'''); + pluginUsingJavaAndNewEmbeddingDir + .childDirectory('android') + .childDirectory('src') + .childDirectory('main') + .childDirectory('java') + .childDirectory('plugin4') + .childFile('UseBothEmbedding.java') + ..createSync(recursive: true) + ..writeAsStringSync( + 'import io.flutter.embedding.engine.plugins.FlutterPlugin;\n' + 'PluginRegistry\n' + 'registerWith(Irrelevant registrar)\n' + ); + + flutterProject.directory + .childFile('.packages') + .writeAsStringSync( + 'plugin4:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()}', + mode: FileMode.append, + ); + } + // Creates the files that would indicate that pod install has run for the // given project. void simulatePodInstallRun(XcodeBasedProject project) { @@ -149,6 +269,7 @@ expect(registrant.existsSync(), isTrue); expect(registrant.readAsStringSync(), contains('package io.flutter.plugins')); expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant')); + expect(registrant.readAsStringSync(), contains('public static void registerWith(PluginRegistry registry)')); }, overrides: <Type, Generator>{ FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -168,6 +289,7 @@ expect(registrant.existsSync(), isTrue); expect(registrant.readAsStringSync(), contains('package io.flutter.plugins')); expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant')); + expect(registrant.readAsStringSync(), contains('public static void registerWith(@NonNull FlutterEngine flutterEngine)')); }, overrides: <Type, Generator>{ FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -178,72 +300,9 @@ when(flutterProject.isModule).thenReturn(false); when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2); - final Directory pluginUsingJavaAndNewEmbeddingDir = - fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.'); - pluginUsingJavaAndNewEmbeddingDir - .childFile('pubspec.yaml') - .writeAsStringSync(''' - flutter: - plugin: - androidPackage: plugin1 - pluginClass: UseNewEmbedding - '''); - pluginUsingJavaAndNewEmbeddingDir - .childDirectory('android') - .childDirectory('src') - .childDirectory('main') - .childDirectory('java') - .childDirectory('plugin1') - .childFile('UseNewEmbedding.java') - ..createSync(recursive: true) - ..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin;'); - - final Directory pluginUsingKotlinAndNewEmbeddingDir = - fs.systemTempDirectory.createTempSync('flutter_plugin_using_kotlin_and_new_embedding_dir.'); - pluginUsingKotlinAndNewEmbeddingDir - .childFile('pubspec.yaml') - .writeAsStringSync(''' - flutter: - plugin: - androidPackage: plugin2 - pluginClass: UseNewEmbedding - '''); - pluginUsingKotlinAndNewEmbeddingDir - .childDirectory('android') - .childDirectory('src') - .childDirectory('main') - .childDirectory('kotlin') - .childDirectory('plugin2') - .childFile('UseNewEmbedding.kt') - ..createSync(recursive: true) - ..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin'); - - final Directory pluginUsingOldEmbeddingDir = - fs.systemTempDirectory.createTempSync('flutter_plugin_using_old_embedding_dir.'); - pluginUsingOldEmbeddingDir - .childFile('pubspec.yaml') - .writeAsStringSync(''' - flutter: - plugin: - androidPackage: plugin3 - pluginClass: UseOldEmbedding - '''); - pluginUsingOldEmbeddingDir - .childDirectory('android') - .childDirectory('src') - .childDirectory('main') - .childDirectory('java') - .childDirectory('plugin3') - .childFile('UseOldEmbedding.java') - ..createSync(recursive: true); - - flutterProject.directory - .childFile('.packages') - .writeAsStringSync(''' -plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()} -plugin2:${pluginUsingKotlinAndNewEmbeddingDir.childDirectory('lib').uri.toString()} -plugin3:${pluginUsingOldEmbeddingDir.childDirectory('lib').uri.toString()} -'''); + createNewJavaPlugin1(); + createNewKotlinPlugin2(); + createOldJavaPlugin3(); await injectPlugins(flutterProject); @@ -258,6 +317,8 @@ expect(registrant.readAsStringSync(), contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));')); + // There should be no warning message + expect(testLogger.statusText, isNot(contains('go/android-plugin-migration'))); }, overrides: <Type, Generator>{ FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -269,31 +330,8 @@ when(flutterProject.isModule).thenReturn(false); when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1); - final Directory pluginUsingJavaAndNewEmbeddingDir = - fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.'); - pluginUsingJavaAndNewEmbeddingDir - .childFile('pubspec.yaml') - .writeAsStringSync(''' - flutter: - plugin: - androidPackage: plugin1 - pluginClass: UseNewEmbedding - '''); - pluginUsingJavaAndNewEmbeddingDir - .childDirectory('android') - .childDirectory('src') - .childDirectory('main') - .childDirectory('java') - .childDirectory('plugin1') - .childFile('UseNewEmbedding.java') - ..createSync(recursive: true) - ..writeAsStringSync('import io.flutter.embedding.engine.plugins.FlutterPlugin;'); + createNewJavaPlugin1(); - flutterProject.directory - .childFile('.packages') - .writeAsStringSync(''' -plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()} -'''); await expectLater( () async { await injectPlugins(flutterProject); @@ -310,39 +348,12 @@ XcodeProjectInterpreter: () => xcodeProjectInterpreter, }); - testUsingContext('allows app use a plugin that supports v1 and v2 embedding', () async { + testUsingContext('old embedding app uses a plugin that supports v1 and v2 embedding', () async { when(flutterProject.isModule).thenReturn(false); when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1); - final Directory pluginUsingJavaAndNewEmbeddingDir = - fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.'); - pluginUsingJavaAndNewEmbeddingDir - .childFile('pubspec.yaml') - .writeAsStringSync(''' - flutter: - plugin: - androidPackage: plugin1 - pluginClass: UseNewEmbedding - '''); - pluginUsingJavaAndNewEmbeddingDir - .childDirectory('android') - .childDirectory('src') - .childDirectory('main') - .childDirectory('java') - .childDirectory('plugin1') - .childFile('UseNewEmbedding.java') - ..createSync(recursive: true) - ..writeAsStringSync( - 'import io.flutter.embedding.engine.plugins.FlutterPlugin;\n' - 'PluginRegistry\n' - 'registerWith(Irrelevant registrar)\n' - ); + createDualSupportJavaPlugin4(); - flutterProject.directory - .childFile('.packages') - .writeAsStringSync(''' -plugin1:${pluginUsingJavaAndNewEmbeddingDir.childDirectory('lib').uri.toString()} -'''); await injectPlugins(flutterProject); final File registrant = flutterProject.directory @@ -352,6 +363,8 @@ expect(registrant.existsSync(), isTrue); expect(registrant.readAsStringSync(), contains('package io.flutter.plugins')); expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant')); + expect(registrant.readAsStringSync(), + contains('UseBothEmbedding.registerWith(registry.registrarFor("plugin4.UseBothEmbedding"));')); }, overrides: <Type, Generator>{ FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -359,9 +372,11 @@ XcodeProjectInterpreter: () => xcodeProjectInterpreter, }); - testUsingContext('Registrant doesn\'t use new embedding if app doesn\'t use new embedding', () async { + testUsingContext('new embedding app uses a plugin that supports v1 and v2 embedding', () async { when(flutterProject.isModule).thenReturn(false); - when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1); + when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2); + + createDualSupportJavaPlugin4(); await injectPlugins(flutterProject); @@ -372,32 +387,16 @@ expect(registrant.existsSync(), isTrue); expect(registrant.readAsStringSync(), contains('package io.flutter.plugins')); expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant')); + expect(registrant.readAsStringSync(), + contains('flutterEngine.getPlugins().add(new plugin4.UseBothEmbedding());')); }, overrides: <Type, Generator>{ FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), FeatureFlags: () => featureFlags, + XcodeProjectInterpreter: () => xcodeProjectInterpreter, }); - testUsingContext('Registrant uses old embedding in module project', () async { - when(flutterProject.isModule).thenReturn(true); - when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1); - - await injectPlugins(flutterProject); - - final File registrant = flutterProject.directory - .childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'io', 'flutter', 'plugins')) - .childFile('GeneratedPluginRegistrant.java'); - - expect(registrant.existsSync(), isTrue); - expect(registrant.readAsStringSync(), contains('package io.flutter.plugins')); - expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant')); - }, overrides: <Type, Generator>{ - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - FeatureFlags: () => featureFlags, - }); - - testUsingContext('Registrant uses new embedding if module uses new embedding', () async { + testUsingContext('Modules use new embedding', () async { when(flutterProject.isModule).thenReturn(true); when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2); @@ -410,29 +409,76 @@ expect(registrant.existsSync(), isTrue); expect(registrant.readAsStringSync(), contains('package io.flutter.plugins')); expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant')); + expect(registrant.readAsStringSync(), contains('public static void registerWith(@NonNull FlutterEngine flutterEngine)')); }, overrides: <Type, Generator>{ FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), FeatureFlags: () => featureFlags, }); - testUsingContext('Registrant doesn\'t use new embedding if module doesn\'t use new embedding', () async { + testUsingContext('Module using old plugin shows warning', () async { when(flutterProject.isModule).thenReturn(true); - when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1); + when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2); + + createOldJavaPlugin3(); await injectPlugins(flutterProject); final File registrant = flutterProject.directory .childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'io', 'flutter', 'plugins')) .childFile('GeneratedPluginRegistrant.java'); - - expect(registrant.existsSync(), isTrue); - expect(registrant.readAsStringSync(), contains('package io.flutter.plugins')); - expect(registrant.readAsStringSync(), contains('class GeneratedPluginRegistrant')); + expect(registrant.readAsStringSync(), + contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));')); + expect(testLogger.statusText, contains('The plugin `plugin3` is built using an older version of the Android plugin API')); }, overrides: <Type, Generator>{ FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), FeatureFlags: () => featureFlags, + XcodeProjectInterpreter: () => xcodeProjectInterpreter, + }); + + testUsingContext('Module using new plugin shows no warnings', () async { + when(flutterProject.isModule).thenReturn(true); + when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2); + + createNewJavaPlugin1(); + + await injectPlugins(flutterProject); + + final File registrant = flutterProject.directory + .childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'io', 'flutter', 'plugins')) + .childFile('GeneratedPluginRegistrant.java'); + expect(registrant.readAsStringSync(), + contains('flutterEngine.getPlugins().add(new plugin1.UseNewEmbedding());')); + + expect(testLogger.statusText, isNot(contains('go/android-plugin-migration'))); + }, overrides: <Type, Generator>{ + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + FeatureFlags: () => featureFlags, + XcodeProjectInterpreter: () => xcodeProjectInterpreter, + }); + + testUsingContext('Module using plugin with v1 and v2 support shows no warning', () async { + when(flutterProject.isModule).thenReturn(true); + when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2); + + createDualSupportJavaPlugin4(); + + await injectPlugins(flutterProject); + + final File registrant = flutterProject.directory + .childDirectory(fs.path.join('android', 'app', 'src', 'main', 'java', 'io', 'flutter', 'plugins')) + .childFile('GeneratedPluginRegistrant.java'); + expect(registrant.readAsStringSync(), + contains('flutterEngine.getPlugins().add(new plugin4.UseBothEmbedding());')); + + expect(testLogger.statusText, isNot(contains('go/android-plugin-migration'))); + }, overrides: <Type, Generator>{ + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + FeatureFlags: () => featureFlags, + XcodeProjectInterpreter: () => xcodeProjectInterpreter, }); testUsingContext('Does not throw when AndroidManifest.xml is not found', () async {