From 0a08f8afffb129f46610b18c528dbed058ca82c4 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 1 Dec 2020 09:53:07 -0800 Subject: [PATCH] [flutter_tools] Display "no platforms" message based on results when creating plugins project (#70215) --- .../lib/src/commands/create.dart | 133 +++++++++--------- .../lib/src/flutter_manifest.dart | 18 +++ .../templates/plugin/pubspec.yaml.tmpl | 2 +- .../commands.shard/permeable/create_test.dart | 79 +++++++++-- .../general.shard/flutter_manifest_test.dart | 43 ++++++ 5 files changed, 200 insertions(+), 75 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index 3b51c0493e4..0789ec7454d 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:yaml/yaml.dart'; - import '../android/gradle_utils.dart' as gradle; import '../base/common.dart'; import '../base/context.dart'; @@ -17,19 +15,11 @@ import '../features.dart'; import '../flutter_manifest.dart'; import '../flutter_project_metadata.dart'; import '../globals.dart' as globals; -import '../plugins.dart'; import '../project.dart'; import '../reporting/reporting.dart'; import '../runner/flutter_command.dart'; import 'create_base.dart'; -const String _kNoPlatformsErrorMessage = ''' -The plugin project was generated without specifying the `--platforms` flag, no new platforms are added. -To add platforms, run `flutter create -t plugin --platforms .` under the same -directory. You can also find detailed instructions on how to add platforms in the `pubspec.yaml` -at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms. -'''; - class CreateCommand extends CreateBase { CreateCommand() { addPlatformsOptions(customHelp: 'The platforms supported by this project. ' @@ -249,7 +239,8 @@ class CreateCommand extends CreateBase { ); final String relativeDirPath = globals.fs.path.relative(projectDirPath); - if (!projectDir.existsSync() || projectDir.listSync().isEmpty) { + final bool creatingNewProject = !projectDir.existsSync() || projectDir.listSync().isEmpty; + if (creatingNewProject) { globals.printStatus('Creating project $relativeDirPath...'); } else { if (sampleCode != null && !overwrite) { @@ -295,18 +286,24 @@ class CreateCommand extends CreateBase { 'main.dart', )); globals.printStatus('Your module code is in $relativeMainPath.'); - } else { + } else if (generatePlugin) { + final String relativePluginPath = globals.fs.path.normalize(globals.fs.path.relative(projectDirPath)); + final List requestedPlatforms = _getUserRequestedPlatforms(); + final String platformsString = requestedPlatforms.join(', '); + _printPluginDirectoryLocationMessage(relativePluginPath, projectName, platformsString); + if (!creatingNewProject && requestedPlatforms.isNotEmpty) { + _printPluginUpdatePubspecMessage(relativePluginPath, platformsString); + } else if (_getSupportedPlatformsInPlugin(projectDir).isEmpty){ + globals.printError(_kNoPlatformsArgMessage); + } + } else { // Tell the user the next steps. final FlutterProject project = FlutterProject.fromPath(projectDirPath); final FlutterProject app = project.hasExampleApp ? project.example : project; final String relativeAppPath = globals.fs.path.normalize(globals.fs.path.relative(app.directory.path)); final String relativeAppMain = globals.fs.path.join(relativeAppPath, 'lib', 'main.dart'); - final String relativePluginPath = globals.fs.path.normalize(globals.fs.path.relative(projectDirPath)); - final String relativePluginMain = globals.fs.path.join(relativePluginPath, 'lib', '$projectName.dart'); // Let them know a summary of the state of their tooling. - final List platforms = _getSupportedPlatformsFromTemplateContext(templateContext); - final String platformsString = platforms.join(', '); globals.printStatus(''' In order to run your $application, type: @@ -315,14 +312,6 @@ In order to run your $application, type: Your $application code is in $relativeAppMain. '''); - if (generatePlugin) { - globals.printStatus(''' -Your plugin code is in $relativePluginMain. - -Host platform code is in the $platformsString directories under $relativePluginPath. -To edit platform code in an IDE see https://flutter.dev/developing-packages/#edit-plugin-package. -'''); - } } return FlutterCommandResult.success(); } @@ -378,19 +367,13 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi templateContext['linux'] = false; templateContext['macos'] = false; templateContext['windows'] = false; - globals.printError(_kNoPlatformsErrorMessage); } final List platformsToAdd = _getSupportedPlatformsFromTemplateContext(templateContext); - final String pubspecPath = globals.fs.path.join(directory.absolute.path, 'pubspec.yaml'); - final FlutterManifest manifest = FlutterManifest.createFromPath(pubspecPath, fileSystem: globals.fs, logger: globals.logger); - List existingPlatforms = []; - if (manifest.supportedPlatforms != null) { - existingPlatforms = manifest.supportedPlatforms.keys.toList(); - for (final String existingPlatform in existingPlatforms) { - // re-generate files for existing platforms - templateContext[existingPlatform] = true; - } + final List existingPlatforms = _getSupportedPlatformsInPlugin(directory); + for (final String existingPlatform in existingPlatforms) { + // re-generate files for existing platforms + templateContext[existingPlatform] = true; } final bool willAddPlatforms = platformsToAdd.isNotEmpty; @@ -411,35 +394,6 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi ); } - final bool addPlatformsToExistingPlugin = willAddPlatforms && existingPlatforms.isNotEmpty; - - if (addPlatformsToExistingPlugin) { - // If adding new platforms to an existing plugin project, prints - // a help message containing the platforms maps need to be added to the `platforms` key in the pubspec. - platformsToAdd.removeWhere(existingPlatforms.contains); - final YamlMap platformsMapToPrint = Plugin.createPlatformsYamlMap(platformsToAdd, templateContext['pluginClass'] as String, templateContext['androidIdentifier'] as String); - if (platformsMapToPrint.isNotEmpty) { - String prettyYaml = ''; - for (final String platform in platformsMapToPrint.keys.toList().cast()) { - prettyYaml += '$platform:\n'; - for (final String key in (platformsMapToPrint[platform] as YamlMap).keys.toList().cast()) { - prettyYaml += ' $key: ${platformsMapToPrint[platform][key] as String}\n'; - } - } - globals.printStatus(''' -The `pubspec.yaml` under the project directory must be updated to support ${platformsToAdd.join(', ')}, -Add below lines to under the `platform:` key: -''', emphasis: true); - globals.printStatus(prettyYaml, emphasis: true, color: TerminalColor.blue); - globals.printStatus(''' -If the `platforms` key does not exist in the `pubspec.yaml`, it might because that the plugin project does not -use the multi-platforms plugin format. We highly recommend a migration to the multi-platforms plugin format. -For detailed instructions on how to format the pubspec.yaml to support platforms using the multi-platforms format, see: -https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms -''', emphasis: true); - } - } - final FlutterProject project = FlutterProject.fromDirectory(directory); final bool generateAndroid = templateContext['android'] == true; if (generateAndroid) { @@ -493,4 +447,57 @@ https://flutter.dev/docs/development/packages-and-plugins/developing-packages#pl 'macos', ]; } + + // Returns a list of platforms that are explicitly requested by user via `--platforms`. + List _getUserRequestedPlatforms() { + if (!argResults.wasParsed('platforms')) { + return []; + } + return stringsArg('platforms'); + } } + + +// Determine what platforms are supported based on generated files. +List _getSupportedPlatformsInPlugin(Directory projectDir) { + final String pubspecPath = globals.fs.path.join(projectDir.absolute.path, 'pubspec.yaml'); + final FlutterManifest manifest = FlutterManifest.createFromPath(pubspecPath, fileSystem: globals.fs, logger: globals.logger); + final List platforms = manifest.validSupportedPlatforms == null + ? [] + : manifest.validSupportedPlatforms.keys.toList(); + return platforms; +} + +void _printPluginDirectoryLocationMessage(String pluginPath, String projectName, String platformsString) { + final String relativePluginMain = globals.fs.path.join(pluginPath, 'lib', '$projectName.dart'); + final String relativeExampleMain = globals.fs.path.join(pluginPath, 'example', 'lib', 'main.dart'); + globals.printStatus(''' + +Your plugin code is in $relativePluginMain. + +You example app code is in $relativeExampleMain. + +'''); + if (platformsString != null && platformsString.isNotEmpty) { + globals.printStatus(''' +Host platform code is in the $platformsString directories under $pluginPath. +To edit platform code in an IDE see https://flutter.dev/developing-packages/#edit-plugin-package. + + '''); + } +} + +void _printPluginUpdatePubspecMessage(String pluginPath, String platformsString) { + globals.printStatus(''' + +You need to update $pluginPath/pubspec.yaml to support $platformsString. +For more information, see https://flutter.dev/go/developing-plugins. + +''', emphasis: true, color: TerminalColor.red); +} + +const String _kNoPlatformsArgMessage = ''' + +Must specify at least one platform using --platforms. +For more information, see https://flutter.dev/go/developing-plugins. +'''; diff --git a/packages/flutter_tools/lib/src/flutter_manifest.dart b/packages/flutter_tools/lib/src/flutter_manifest.dart index b9412789782..af678d555bf 100644 --- a/packages/flutter_tools/lib/src/flutter_manifest.dart +++ b/packages/flutter_tools/lib/src/flutter_manifest.dart @@ -12,6 +12,10 @@ import 'base/user_messages.dart'; import 'base/utils.dart'; import 'plugins.dart'; +const Set _kValidPluginPlatforms = { + 'android', 'ios', 'web', 'windows', 'linux', 'macos' +}; + /// A wrapper around the `flutter` section in the `pubspec.yaml` file. class FlutterManifest { FlutterManifest._(this._logger); @@ -199,6 +203,20 @@ class FlutterManifest { return null; } + /// Like [supportedPlatforms], but only returns the valid platforms that are supported in flutter plugins. + Map get validSupportedPlatforms { + final Map allPlatforms = supportedPlatforms; + if (allPlatforms == null) { + return null; + } + final Map platforms = {}..addAll(supportedPlatforms); + platforms.removeWhere((String key, dynamic _) => !_kValidPluginPlatforms.contains(key)); + if (platforms.isEmpty) { + return null; + } + return platforms; + } + List> get fontsDescriptor { return fonts.map((Font font) => font.descriptor).toList(); } diff --git a/packages/flutter_tools/templates/plugin/pubspec.yaml.tmpl b/packages/flutter_tools/templates/plugin/pubspec.yaml.tmpl index 4ce3f0dbb06..7ec1aeb5897 100644 --- a/packages/flutter_tools/templates/plugin/pubspec.yaml.tmpl +++ b/packages/flutter_tools/templates/plugin/pubspec.yaml.tmpl @@ -33,7 +33,7 @@ flutter: platforms: {{#no_platforms}} # This plugin project was generated without specifying any - # platforms with the `--platform` argument. If you see the `fake_platform` map below, remove it and + # platforms with the `--platform` argument. If you see the `some_platform` map below, remove it and # then add platforms following the instruction here: # https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms # ------------------- diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 30ecc6da1e5..71d53d12acb 100755 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -32,6 +32,7 @@ import '../../src/context.dart'; import '../../src/pubspec_schema.dart'; import '../../src/testbed.dart'; +const String _kNoPlatformsMessage = 'Must specify at least one platform using --platforms.\n'; const String frameworkRevision = '12345678'; const String frameworkChannel = 'omega'; // TODO(fujino): replace FakePlatform.fromPlatform() with FakePlatform() @@ -390,8 +391,6 @@ void main() { 'android/src/main/java/com/example/flutter_project/FlutterProjectPlugin.java', 'example/android/app/src/main/java/com/example/flutter_project_example/MainActivity.java', 'lib/flutter_project_web.dart', - // TODO(cyanglaz): no-op iOS folder should be removed after 1.20.0 release - // https://github.com/flutter/flutter/issues/59787 ], ); return _runFlutterTest(projectDir.childDirectory('example')); @@ -422,6 +421,7 @@ void main() { // The platform is correctly registered expect(pubspec.flutter['plugin']['platforms']['web']['pluginClass'], 'FlutterProjectWeb'); expect(pubspec.flutter['plugin']['platforms']['web']['fileName'], 'flutter_project_web.dart'); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), Pub: () => Pub( @@ -432,6 +432,7 @@ void main() { botDetector: globals.botDetector, platform: globals.platform, ), + Logger: ()=>logger, }); testUsingContext('plugin example app depends on plugin', () async { @@ -661,7 +662,9 @@ void main() { // Import for the new embedding class. expect(mainActivity.contains('import io.flutter.embedding.android.FlutterActivity'), true); - expect(testLogger.statusText, isNot(contains('https://flutter.dev/go/android-project-migration'))); + expect(logger.statusText, isNot(contains('https://flutter.dev/go/android-project-migration'))); + }, overrides: { + Logger: () => logger, }); testUsingContext('app does not include desktop or web by default', () async { @@ -732,8 +735,10 @@ void main() { expect(projectDir.childDirectory('windows'), isNot(exists)); expect(projectDir.childDirectory('macos'), isNot(exists)); expect(projectDir.childDirectory('web'), isNot(exists)); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), + Logger: () => logger, }); testUsingContext('plugin supports Linux if requested', () async { @@ -767,8 +772,10 @@ void main() { ], pluginClass: 'FlutterProjectPlugin', unexpectedPlatforms: ['some_platform']); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), + Logger: () => logger, }); testUsingContext('app supports macOS if requested', () async { @@ -794,8 +801,10 @@ void main() { expect(projectDir.childDirectory('linux'), isNot(exists)); expect(projectDir.childDirectory('windows'), isNot(exists)); expect(projectDir.childDirectory('web'), isNot(exists)); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), + Logger: () => logger, }); testUsingContext('plugin supports macOS if requested', () async { @@ -826,8 +835,10 @@ void main() { 'macos', ], pluginClass: 'FlutterProjectPlugin', unexpectedPlatforms: ['some_platform']); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), + Logger: () => logger, }); testUsingContext('app supports Windows if requested', () async { @@ -852,8 +863,10 @@ void main() { expect(projectDir.childDirectory('linux'), isNot(exists)); expect(projectDir.childDirectory('macos'), isNot(exists)); expect(projectDir.childDirectory('web'), isNot(exists)); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), + Logger: () => logger, }); testUsingContext('Windows has correct VERSIONINFO', () async { @@ -914,8 +927,10 @@ void main() { 'windows' ], pluginClass: 'FlutterProjectPlugin', unexpectedPlatforms: ['some_platform']); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), + Logger: () => logger, }); testUsingContext('app supports web if requested', () async { @@ -941,8 +956,10 @@ void main() { expect(projectDir.childDirectory('linux'), isNot(exists)); expect(projectDir.childDirectory('macos'), isNot(exists)); expect(projectDir.childDirectory('windows'), isNot(exists)); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), + Logger: () => logger, }); testUsingContext('plugin uses new platform schema', () async { @@ -1652,8 +1669,6 @@ void main() { await runner.run(['create', '--no-pub', '--template=plugin', projectDir.path]); - // TODO(cyanglaz): no-op iOS folder should be removed after 1.20.0 release - // https://github.com/flutter/flutter/issues/59787 expect(projectDir.childDirectory('ios'), isNot(exists)); expect(projectDir.childDirectory('android'), isNot(exists)); expect(projectDir.childDirectory('web'), isNot(exists)); @@ -1661,8 +1676,6 @@ void main() { expect(projectDir.childDirectory('windows'), isNot(exists)); expect(projectDir.childDirectory('macos'), isNot(exists)); - // TODO(cyanglaz): no-op iOS folder should be removed after 1.20.0 release - // https://github.com/flutter/flutter/issues/59787 expect(projectDir.childDirectory('example').childDirectory('ios'), isNot(exists)); expect(projectDir.childDirectory('example').childDirectory('android'), @@ -1683,7 +1696,6 @@ void main() { FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false), }); - testUsingContext('plugin supports ios if requested', () async { Cache.flutterRoot = '../..'; when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision); @@ -1700,8 +1712,10 @@ void main() { 'ios', ], pluginClass: 'FlutterProjectPlugin', unexpectedPlatforms: ['some_platform']); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false), + Logger: () => logger, }); testUsingContext('plugin supports android if requested', () async { @@ -1722,8 +1736,10 @@ void main() { ], pluginClass: 'FlutterProjectPlugin', unexpectedPlatforms: ['some_platform'], androidIdentifier: 'com.example.flutter_project'); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false), + Logger: () => logger, }); testUsingContext('plugin supports web if requested', () async { @@ -1744,8 +1760,10 @@ void main() { unexpectedPlatforms: ['some_platform'], androidIdentifier: 'com.example.flutter_project', webFileName: 'flutter_project_web.dart'); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); }, overrides: { FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), + Logger: () => logger, }); testUsingContext('plugin doe not support web if feature is not enabled', () async { @@ -1764,8 +1782,10 @@ void main() { 'some_platform' ], pluginClass: 'somePluginClass', unexpectedPlatforms: ['web']); + expect(logger.errorText, contains(_kNoPlatformsMessage)); }, overrides: { FeatureFlags: () => TestFeatureFlags(isWebEnabled: false), + Logger: () => logger, }); testUsingContext('create an empty plugin, then add ios', () async { @@ -2081,7 +2101,9 @@ void main() { final CreateCommand command = CreateCommand(); final CommandRunner runner = createTestCommandRunner(command); await runner.run(['create', '--no-pub', '--template=plugin', '--platforms=android', projectDir.path]); - expect(logger.statusText, isNot(contains('The `pubspec.yaml` under the project directory must be updated to support'))); + final String projectDirPath = globals.fs.path.normalize(projectDir.absolute.path); + final String relativePluginPath = globals.fs.path.normalize(globals.fs.path.relative(projectDirPath)); + expect(logger.statusText, isNot(contains('You need to update $relativePluginPath/pubspec.yaml to support android.\n'))); }, overrides: { Logger: () => logger, }); @@ -2093,10 +2115,12 @@ void main() { final CreateCommand command = CreateCommand(); final CommandRunner runner = createTestCommandRunner(command); + final String projectDirPath = globals.fs.path.normalize(projectDir.absolute.path); + final String relativePluginPath = globals.fs.path.normalize(globals.fs.path.relative(projectDirPath)); await runner.run(['create', '--no-pub', '--template=plugin', '--platforms=ios', projectDir.path]); - expect(logger.statusText, isNot(contains('The `pubspec.yaml` under the project directory must be updated to support'))); + expect(logger.statusText, isNot(contains('You need to update $relativePluginPath/pubspec.yaml to support ios.\n'))); await runner.run(['create', '--no-pub', '--template=plugin', '--platforms=android', projectDir.path]); - expect(logger.statusText, contains('The `pubspec.yaml` under the project directory must be updated to support')); + expect(logger.statusText, contains('You need to update $relativePluginPath/pubspec.yaml to support android.\n')); }, overrides: { Logger: () => logger, }); @@ -2276,6 +2300,39 @@ void main() { }, overrides: { FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), }); + + testUsingContext('created plugin supports no platforms should print `no platforms` message', () async { + Cache.flutterRoot = '../..'; + when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision); + when(mockFlutterVersion.channel).thenReturn(frameworkChannel); + + final CreateCommand command = CreateCommand(); + final CommandRunner runner = createTestCommandRunner(command); + + await runner.run(['create', '--no-pub', '--template=plugin', projectDir.path]); + expect(logger.errorText, contains(_kNoPlatformsMessage)); + + }, overrides: { + FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false), + Logger: ()=> logger, + }); + + testUsingContext('created plugin with no --platforms flag should not print `no platforms` message if the existing plugin supports a platform.', () async { + Cache.flutterRoot = '../..'; + when(mockFlutterVersion.frameworkRevision).thenReturn(frameworkRevision); + when(mockFlutterVersion.channel).thenReturn(frameworkChannel); + + final CreateCommand command = CreateCommand(); + final CommandRunner runner = createTestCommandRunner(command); + + await runner.run(['create', '--no-pub', '--template=plugin', '--platforms=ios', projectDir.path]); + await runner.run(['create', '--no-pub', '--template=plugin', projectDir.path]); + expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); + + }, overrides: { + FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false), + Logger: () => logger, + }); } Future _createProject( diff --git a/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart b/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart index bfc2d78f6fd..998ebc144cb 100644 --- a/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart +++ b/packages/flutter_tools/test/general.shard/flutter_manifest_test.dart @@ -972,6 +972,49 @@ flutter: expect(flutterManifest.supportedPlatforms, null); }); + testWithoutContext('FlutterManifest validSupportedPlatforms return null if the platform keys are not valid', () { + const String manifest = ''' +name: test +flutter: + plugin: + platforms: + some_platform: + pluginClass: SomeClass +'''; + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); + + expect(flutterManifest.isPlugin, true); + expect(flutterManifest.validSupportedPlatforms, null); + }); + + testWithoutContext('FlutterManifest validSupportedPlatforms only returns valid platforms', () { + const String manifest = ''' +name: test +flutter: + plugin: + platforms: + some_platform: + pluginClass: SomeClass + ios: + pluginClass: SomeClass +'''; + final BufferLogger logger = BufferLogger.test(); + final FlutterManifest flutterManifest = FlutterManifest.createFromString( + manifest, + logger: logger, + ); + + expect(flutterManifest.isPlugin, true); + expect(flutterManifest.validSupportedPlatforms['ios'], + {'pluginClass': 'SomeClass'}); + expect(flutterManifest.validSupportedPlatforms['some_platform'], + isNull); + }); + testWithoutContext('FlutterManifest getSupportedPlatforms returns valid platforms.', () { const String manifest = ''' name: test