Add CI steps to test iOS and macOS plugins with both CocoaPods and Swift Package Manager (#6557)

Tests new Swift Package Manager feature added in https://github.com/flutter/flutter/pull/146256.

Fixes https://github.com/flutter/flutter/issues/146901.
diff --git a/.ci/targets/ios_platform_tests.yaml b/.ci/targets/ios_platform_tests.yaml
index b961b67..e679834 100644
--- a/.ci/targets/ios_platform_tests.yaml
+++ b/.ci/targets/ios_platform_tests.yaml
@@ -11,7 +11,7 @@
     infra_step: true
   - name: build examples
     script: .ci/scripts/tool_runner.sh
-    args: ["build-examples", "--ios"]
+    args: ["build-examples", "--ios", "--swift-package-manager"]
   - name: xcode analyze
     script: .ci/scripts/tool_runner.sh
     args: ["xcode-analyze", "--ios"]
diff --git a/.ci/targets/macos_platform_tests.yaml b/.ci/targets/macos_platform_tests.yaml
index bc1b915..1dd105f 100644
--- a/.ci/targets/macos_platform_tests.yaml
+++ b/.ci/targets/macos_platform_tests.yaml
@@ -8,7 +8,7 @@
     infra_step: true
   - name: build examples
     script: .ci/scripts/tool_runner.sh
-    args: ["build-examples", "--macos"]
+    args: ["build-examples", "--macos", "--swift-package-manager"]
   - name: xcode analyze
     script: .ci/scripts/tool_runner.sh
     args: ["xcode-analyze", "--macos"]
diff --git a/script/tool/lib/src/build_examples_command.dart b/script/tool/lib/src/build_examples_command.dart
index 0f78d39..d8d1613 100644
--- a/script/tool/lib/src/build_examples_command.dart
+++ b/script/tool/lib/src/build_examples_command.dart
@@ -38,6 +38,9 @@
 
 const String _flutterBuildTypeAndroidAlias = 'android';
 
+/// Key for Swift Package Manager.
+const String _swiftPackageManagerFlag = 'swift-package-manager';
+
 /// A command to build the example applications for packages.
 class BuildExamplesCommand extends PackageLoopingCommand {
   /// Creates an instance of the build command.
@@ -58,6 +61,7 @@
       defaultsTo: '',
       help: 'Enables the given Dart SDK experiments.',
     );
+    argParser.addFlag(_swiftPackageManagerFlag);
   }
 
   // Maps the switch this command uses to identify a platform to information
@@ -111,6 +115,15 @@
       'single key "$_pluginToolsConfigGlobalKey" containing a list of build '
       'arguments.';
 
+  /// Returns true if `--swift-package-manager` flag was passed along with
+  /// either `--ios` or `--macos`.
+  bool get usingSwiftPackageManager {
+    final List<String> platformFlags = _platforms.keys.toList();
+    return getBoolArg(_swiftPackageManagerFlag) &&
+        (platformFlags.contains(platformIOS) ||
+            platformFlags.contains(platformMacOS));
+  }
+
   @override
   Future<void> initializeRun() async {
     final List<String> platformFlags = _platforms.keys.toList();
@@ -121,6 +134,17 @@
           'were specified. At least one platform must be provided.');
       throw ToolExit(_exitNoPlatformFlags);
     }
+
+    // TODO(vashworth): Enable on stable once Swift Package Manager feature is
+    // available on stable.
+    if (usingSwiftPackageManager &&
+        platform.environment['CHANNEL'] != 'stable') {
+      await processRunner.runAndStream(
+        flutterCommand,
+        <String>['config', '--enable-swift-package-manager'],
+        exitOnError: true,
+      );
+    }
   }
 
   @override
diff --git a/script/tool/test/build_examples_command_test.dart b/script/tool/test/build_examples_command_test.dart
index 2f58dac..0c99bfb 100644
--- a/script/tool/test/build_examples_command_test.dart
+++ b/script/tool/test/build_examples_command_test.dart
@@ -164,6 +164,98 @@
           ]));
     });
 
+    test('building for iOS with Swift Package Manager on master channel',
+        () async {
+      mockPlatform.isMacOS = true;
+      mockPlatform.environment['CHANNEL'] = 'master';
+
+      final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir,
+          platformSupport: <String, PlatformDetails>{
+            platformIOS: const PlatformDetails(PlatformSupport.inline),
+          });
+
+      final Directory pluginExampleDirectory = getExampleDir(plugin);
+
+      final List<String> output = await runCapturingPrint(runner, <String>[
+        'build-examples',
+        '--ios',
+        '--enable-experiment=exp1',
+        '--swift-package-manager',
+      ]);
+
+      expect(
+        output,
+        containsAllInOrder(<String>[
+          '\nBUILDING plugin/example for iOS',
+        ]),
+      );
+
+      expect(
+        processRunner.recordedCalls,
+        orderedEquals(<ProcessCall>[
+          ProcessCall(
+            getFlutterCommand(mockPlatform),
+            const <String>['config', '--enable-swift-package-manager'],
+            null,
+          ),
+          ProcessCall(
+            getFlutterCommand(mockPlatform),
+            const <String>[
+              'build',
+              'ios',
+              '--no-codesign',
+              '--enable-experiment=exp1'
+            ],
+            pluginExampleDirectory.path,
+          ),
+        ]),
+      );
+    });
+
+    test(
+        'building for iOS with Swift Package Manager on stable channel does not enable SPM',
+        () async {
+      mockPlatform.isMacOS = true;
+      mockPlatform.environment['CHANNEL'] = 'stable';
+
+      final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir,
+          platformSupport: <String, PlatformDetails>{
+            platformIOS: const PlatformDetails(PlatformSupport.inline),
+          });
+
+      final Directory pluginExampleDirectory = getExampleDir(plugin);
+
+      final List<String> output = await runCapturingPrint(runner, <String>[
+        'build-examples',
+        '--ios',
+        '--enable-experiment=exp1',
+        '--swift-package-manager',
+      ]);
+
+      expect(
+        output,
+        containsAllInOrder(<String>[
+          '\nBUILDING plugin/example for iOS',
+        ]),
+      );
+
+      expect(
+        processRunner.recordedCalls,
+        orderedEquals(<ProcessCall>[
+          ProcessCall(
+            getFlutterCommand(mockPlatform),
+            const <String>[
+              'build',
+              'ios',
+              '--no-codesign',
+              '--enable-experiment=exp1'
+            ],
+            pluginExampleDirectory.path,
+          ),
+        ]),
+      );
+    });
+
     test(
         'building for Linux when plugin is not set up for Linux results in no-op',
         () async {
@@ -261,6 +353,86 @@
           ]));
     });
 
+    test('building for macOS with Swift Package Manager on master channel',
+        () async {
+      mockPlatform.isMacOS = true;
+      mockPlatform.environment['CHANNEL'] = 'master';
+
+      final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir,
+          platformSupport: <String, PlatformDetails>{
+            platformMacOS: const PlatformDetails(PlatformSupport.inline),
+          });
+
+      final Directory pluginExampleDirectory = getExampleDir(plugin);
+
+      final List<String> output = await runCapturingPrint(runner,
+          <String>['build-examples', '--macos', '--swift-package-manager']);
+
+      expect(
+        output,
+        containsAllInOrder(<String>[
+          '\nBUILDING plugin/example for macOS',
+        ]),
+      );
+
+      expect(
+        processRunner.recordedCalls,
+        orderedEquals(<ProcessCall>[
+          ProcessCall(
+            getFlutterCommand(mockPlatform),
+            const <String>['config', '--enable-swift-package-manager'],
+            null,
+          ),
+          ProcessCall(
+            getFlutterCommand(mockPlatform),
+            const <String>[
+              'build',
+              'macos',
+            ],
+            pluginExampleDirectory.path,
+          ),
+        ]),
+      );
+    });
+
+    test(
+        'building for macOS with Swift Package Manager on stable channel does not enable SPM',
+        () async {
+      mockPlatform.isMacOS = true;
+      mockPlatform.environment['CHANNEL'] = 'stable';
+
+      final RepositoryPackage plugin = createFakePlugin('plugin', packagesDir,
+          platformSupport: <String, PlatformDetails>{
+            platformMacOS: const PlatformDetails(PlatformSupport.inline),
+          });
+
+      final Directory pluginExampleDirectory = getExampleDir(plugin);
+
+      final List<String> output = await runCapturingPrint(runner,
+          <String>['build-examples', '--macos', '--swift-package-manager']);
+
+      expect(
+        output,
+        containsAllInOrder(<String>[
+          '\nBUILDING plugin/example for macOS',
+        ]),
+      );
+
+      expect(
+        processRunner.recordedCalls,
+        orderedEquals(<ProcessCall>[
+          ProcessCall(
+            getFlutterCommand(mockPlatform),
+            const <String>[
+              'build',
+              'macos',
+            ],
+            pluginExampleDirectory.path,
+          ),
+        ]),
+      );
+    });
+
     test('building for web with no implementation results in no-op', () async {
       createFakePlugin('plugin', packagesDir);