[tool] Add a telemetry event to track SwiftPM migration (#166773)

Flutter is migrating from CocoaPods to Swift Package Manager to manage
native dependencies on iOS and macOS. We'd like to answer the following
questions:

1. Can we remove CocoaPods support from Flutter's tooling?
2. Can we tell plugin authors that they can remove CocoaPods integration
from their plugins?

This makes the Flutter tool send an event when it injects plugins into
an iOS or macOS project. This will happen whenever a user does commands
like `flutter build ios`, `flutter build macos`, and more.

Part of https://github.com/flutter/flutter/issues/147602

Depends on: https://github.com/dart-lang/tools/pull/2062

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
Loïc Sharma 2025-04-29 12:11:50 -07:00 committed by GitHub
parent a46bf190ef
commit 7141eb3bdc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 388 additions and 128 deletions

View File

@ -1327,7 +1327,9 @@ Future<void> injectPlugins(
templateRenderer: globals.templateRenderer,
),
fileSystem: globals.fs,
featureFlags: featureFlags,
logger: globals.logger,
analytics: globals.analytics,
);
if (iosPlatform) {
await darwinDependencyManagerSetup.setUp(platform: SupportedPlatform.ios);

View File

@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:unified_analytics/unified_analytics.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/logger.dart';
import '../features.dart';
import '../plugins.dart';
import '../project.dart';
import 'cocoapods.dart';
@ -21,20 +24,26 @@ class DarwinDependencyManagement {
required CocoaPods cocoapods,
required SwiftPackageManager swiftPackageManager,
required FileSystem fileSystem,
required FeatureFlags featureFlags,
required Logger logger,
required Analytics analytics,
}) : _project = project,
_plugins = plugins,
_cocoapods = cocoapods,
_swiftPackageManager = swiftPackageManager,
_fileSystem = fileSystem,
_logger = logger;
_featureFlags = featureFlags,
_logger = logger,
_analytics = analytics;
final FlutterProject _project;
final List<Plugin> _plugins;
final CocoaPods _cocoapods;
final SwiftPackageManager _swiftPackageManager;
final FileSystem _fileSystem;
final FeatureFlags _featureFlags;
final Logger _logger;
final Analytics _analytics;
/// Generates/updates required files and project settings for Darwin
/// Dependency Managers (CocoaPods and Swift Package Manager). Projects may
@ -87,6 +96,7 @@ class DarwinDependencyManagement {
// whether to run.
useCocoapods = _plugins.isNotEmpty;
}
if (useCocoapods) {
await _cocoapods.setupPodfile(xcodeProject);
}
@ -95,6 +105,21 @@ class DarwinDependencyManagement {
else if (xcodeProject.podfile.existsSync() && xcodeProject.podfileLock.existsSync()) {
_cocoapods.addPodsDependencyToFlutterXcconfig(xcodeProject);
}
final Event event = Event.flutterInjectDarwinPlugins(
platform: platform.name,
isModule: _project.isModule,
swiftPackageManagerUsable: xcodeProject.usesSwiftPackageManager,
swiftPackageManagerFeatureEnabled: _featureFlags.isSwiftPackageManagerEnabled,
projectDisabledSwiftPackageManager: _project.manifest.disabledSwiftPackageManager,
projectHasSwiftPackageManagerIntegration:
xcodeProject.flutterPluginSwiftPackageInProjectSettings,
pluginCount: totalCount,
swiftPackageCount: swiftPackageCount,
podCount: podCount,
);
_analytics.send(event);
}
/// Returns count of total number of plugins, number of Swift Package Manager

View File

@ -5,6 +5,7 @@
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/flutter_manifest.dart';
import 'package:flutter_tools/src/macos/cocoapods.dart';
import 'package:flutter_tools/src/macos/darwin_dependency_management.dart';
import 'package:flutter_tools/src/macos/swift_package_manager.dart';
@ -12,8 +13,10 @@ import 'package:flutter_tools/src/platform_plugins.dart';
import 'package:flutter_tools/src/plugins.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:test/fake.dart';
import 'package:unified_analytics/unified_analytics.dart';
import '../../src/common.dart';
import '../../src/fakes.dart';
void main() {
const List<SupportedPlatform> supportedPlatforms = <SupportedPlatform>[
@ -26,16 +29,22 @@ void main() {
group('for ${platform.name}', () {
group('generatePluginsSwiftPackage', () {
testWithoutContext('throw if invalid platform', () async {
final MemoryFileSystem fs = MemoryFileSystem();
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final FakeAnalytics testAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final DarwinDependencyManagement dependencyManagement = DarwinDependencyManagement(
project: FakeFlutterProject(fileSystem: fs),
project: FakeFlutterProject(fileSystem: testFileSystem),
plugins: <Plugin>[],
cocoapods: FakeCocoaPods(),
swiftPackageManager: FakeSwiftPackageManager(),
fileSystem: fs,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(),
logger: testLogger,
analytics: testAnalytics,
);
await expectLater(
@ -48,9 +57,13 @@ void main() {
});
group('when using Swift Package Manager', () {
testWithoutContext('with only CocoaPod plugins', () async {
final MemoryFileSystem fs = MemoryFileSystem();
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final File cocoapodPluginPodspec = fs.file(
final FakeAnalytics fakeAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final File cocoapodPluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1.podspec',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
@ -66,26 +79,51 @@ void main() {
final FakeCocoaPods cocoaPods = FakeCocoaPods();
final DarwinDependencyManagement dependencyManagement = DarwinDependencyManagement(
project: FakeFlutterProject(usesSwiftPackageManager: true, fileSystem: fs),
project: FakeFlutterProject(
usesSwiftPackageManager: true,
fileSystem: testFileSystem,
),
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: fs,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(isSwiftPackageManagerEnabled: true),
logger: testLogger,
analytics: fakeAnalytics,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isTrue);
expect(testLogger.warningText, isEmpty);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isTrue);
expect(
fakeAnalytics.sentEvents,
contains(
Event.flutterInjectDarwinPlugins(
platform: platform.name,
isModule: false,
swiftPackageManagerUsable: true,
swiftPackageManagerFeatureEnabled: true,
projectDisabledSwiftPackageManager: false,
projectHasSwiftPackageManagerIntegration: false,
pluginCount: 1,
swiftPackageCount: 0,
podCount: 1,
),
),
);
});
testWithoutContext(
'with only Swift Package Manager plugins and no pod integration',
() async {
final MemoryFileSystem fs = MemoryFileSystem();
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final File swiftPackagePluginPodspec = fs.file(
final FakeAnalytics testAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final File swiftPackagePluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1/Package.swift',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
@ -99,100 +137,12 @@ void main() {
expectedPlugins: plugins,
);
final FakeCocoaPods cocoaPods = FakeCocoaPods();
final DarwinDependencyManagement dependencyManagement = DarwinDependencyManagement(
project: FakeFlutterProject(usesSwiftPackageManager: true, fileSystem: fs),
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: fs,
logger: testLogger,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isTrue);
expect(testLogger.warningText, isEmpty);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isFalse);
},
);
testWithoutContext(
'with only Swift Package Manager plugins but project not migrated',
() async {
final MemoryFileSystem fs = MemoryFileSystem();
final BufferLogger testLogger = BufferLogger.test();
final File swiftPackagePluginPodspec = fs.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1/Package.swift',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
FakePlugin(
name: 'swift_package_plugin_1',
platforms: <String, PluginPlatform>{platform.name: FakePluginPlatform()},
pluginSwiftPackageManifestPath: swiftPackagePluginPodspec.path,
),
];
final FakeSwiftPackageManager swiftPackageManager = FakeSwiftPackageManager(
expectedPlugins: plugins,
);
final File projectPodfile = fs.file('/path/to/Podfile')
..createSync(recursive: true);
projectPodfile.writeAsStringSync('Standard Podfile template');
final FakeCocoaPods cocoaPods = FakeCocoaPods(podFile: projectPodfile);
final FakeFlutterProject project = FakeFlutterProject(
final FlutterProject project = FakeFlutterProject(
usesSwiftPackageManager: true,
fileSystem: fs,
fileSystem: testFileSystem,
);
final XcodeBasedProject xcodeProject =
platform == SupportedPlatform.ios ? project.ios : project.macos;
xcodeProject.podfile.createSync(recursive: true);
xcodeProject.podfile.writeAsStringSync('Standard Podfile template');
final DarwinDependencyManagement dependencyManagement = DarwinDependencyManagement(
project: project,
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: fs,
logger: testLogger,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isTrue);
expect(testLogger.warningText, isEmpty);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isFalse);
},
);
testWithoutContext(
'with only Swift Package Manager plugins with preexisting standard CocoaPods Podfile',
() async {
final MemoryFileSystem fs = MemoryFileSystem();
final BufferLogger testLogger = BufferLogger.test();
final File swiftPackagePluginPodspec = fs.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1/Package.swift',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
FakePlugin(
name: 'swift_package_plugin_1',
platforms: <String, PluginPlatform>{platform.name: FakePluginPlatform()},
pluginSwiftPackageManifestPath: swiftPackagePluginPodspec.path,
),
];
final FakeSwiftPackageManager swiftPackageManager = FakeSwiftPackageManager(
expectedPlugins: plugins,
);
final File projectPodfile = fs.file('/path/to/Podfile')
..createSync(recursive: true);
projectPodfile.writeAsStringSync('Standard Podfile template');
final FakeCocoaPods cocoaPods = FakeCocoaPods(podFile: projectPodfile);
final FakeFlutterProject project = FakeFlutterProject(
usesSwiftPackageManager: true,
fileSystem: fs,
);
final XcodeBasedProject xcodeProject =
platform == SupportedPlatform.ios ? project.ios : project.macos;
xcodeProject.podfile.createSync(recursive: true);
xcodeProject.podfile.writeAsStringSync('Standard Podfile template');
xcodeProject.xcodeProjectInfoFile.createSync(recursive: true);
xcodeProject.xcodeProjectInfoFile.writeAsStringSync(
'FlutterGeneratedPluginSwiftPackage',
@ -203,8 +153,151 @@ void main() {
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: fs,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(isSwiftPackageManagerEnabled: true),
logger: testLogger,
analytics: testAnalytics,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isTrue);
expect(testLogger.warningText, isEmpty);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isFalse);
expect(
testAnalytics.sentEvents,
contains(
Event.flutterInjectDarwinPlugins(
platform: platform.name,
isModule: false,
swiftPackageManagerUsable: true,
swiftPackageManagerFeatureEnabled: true,
projectDisabledSwiftPackageManager: false,
projectHasSwiftPackageManagerIntegration: true,
pluginCount: 1,
swiftPackageCount: 1,
podCount: 0,
),
),
);
},
);
testWithoutContext(
'with only Swift Package Manager plugins but project not migrated',
() async {
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final FakeAnalytics testAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final File swiftPackagePluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1/Package.swift',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
FakePlugin(
name: 'swift_package_plugin_1',
platforms: <String, PluginPlatform>{platform.name: FakePluginPlatform()},
pluginSwiftPackageManifestPath: swiftPackagePluginPodspec.path,
),
];
final FakeSwiftPackageManager swiftPackageManager = FakeSwiftPackageManager(
expectedPlugins: plugins,
);
final File projectPodfile = testFileSystem.file('/path/to/Podfile')
..createSync(recursive: true);
projectPodfile.writeAsStringSync('Standard Podfile template');
final FakeCocoaPods cocoaPods = FakeCocoaPods(podFile: projectPodfile);
final FakeFlutterProject project = FakeFlutterProject(
usesSwiftPackageManager: true,
fileSystem: testFileSystem,
);
final XcodeBasedProject xcodeProject =
platform == SupportedPlatform.ios ? project.ios : project.macos;
xcodeProject.podfile.createSync(recursive: true);
xcodeProject.podfile.writeAsStringSync('Standard Podfile template');
final DarwinDependencyManagement dependencyManagement = DarwinDependencyManagement(
project: project,
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(isSwiftPackageManagerEnabled: true),
logger: testLogger,
analytics: testAnalytics,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isTrue);
expect(testLogger.warningText, isEmpty);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isFalse);
expect(
testAnalytics.sentEvents,
contains(
Event.flutterInjectDarwinPlugins(
platform: platform.name,
isModule: false,
swiftPackageManagerUsable: true,
swiftPackageManagerFeatureEnabled: true,
projectDisabledSwiftPackageManager: false,
projectHasSwiftPackageManagerIntegration: false,
pluginCount: 1,
swiftPackageCount: 1,
podCount: 0,
),
),
);
},
);
testWithoutContext(
'with only Swift Package Manager plugins with preexisting standard CocoaPods Podfile',
() async {
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final FakeAnalytics testAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final File swiftPackagePluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1/Package.swift',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
FakePlugin(
name: 'swift_package_plugin_1',
platforms: <String, PluginPlatform>{platform.name: FakePluginPlatform()},
pluginSwiftPackageManifestPath: swiftPackagePluginPodspec.path,
),
];
final FakeSwiftPackageManager swiftPackageManager = FakeSwiftPackageManager(
expectedPlugins: plugins,
);
final File projectPodfile = testFileSystem.file('/path/to/Podfile')
..createSync(recursive: true);
projectPodfile.writeAsStringSync('Standard Podfile template');
final FakeCocoaPods cocoaPods = FakeCocoaPods(podFile: projectPodfile);
final FakeFlutterProject project = FakeFlutterProject(
usesSwiftPackageManager: true,
fileSystem: testFileSystem,
);
final XcodeBasedProject xcodeProject =
platform == SupportedPlatform.ios ? project.ios : project.macos;
xcodeProject.podfile.createSync(recursive: true);
xcodeProject.podfile.writeAsStringSync('Standard Podfile template');
xcodeProject.xcodeProjectInfoFile.createSync(recursive: true);
xcodeProject.xcodeProjectInfoFile.writeAsStringSync(
'FlutterGeneratedPluginSwiftPackage',
);
final DarwinDependencyManagement dependencyManagement = DarwinDependencyManagement(
project: project,
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(isSwiftPackageManagerEnabled: true),
logger: testLogger,
analytics: testAnalytics,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isTrue);
@ -226,15 +319,35 @@ void main() {
);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isFalse);
expect(
testAnalytics.sentEvents,
contains(
Event.flutterInjectDarwinPlugins(
platform: platform.name,
isModule: false,
swiftPackageManagerUsable: true,
swiftPackageManagerFeatureEnabled: true,
projectDisabledSwiftPackageManager: false,
projectHasSwiftPackageManagerIntegration: true,
pluginCount: 1,
swiftPackageCount: 1,
podCount: 0,
),
),
);
},
);
testWithoutContext(
'with only Swift Package Manager plugins with preexisting custom CocoaPods Podfile',
() async {
final MemoryFileSystem fs = MemoryFileSystem();
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final File swiftPackagePluginPodspec = fs.file(
final FakeAnalytics testAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final File swiftPackagePluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1/Package.swift',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
@ -247,13 +360,13 @@ void main() {
final FakeSwiftPackageManager swiftPackageManager = FakeSwiftPackageManager(
expectedPlugins: plugins,
);
final File projectPodfile = fs.file('/path/to/Podfile')
final File projectPodfile = testFileSystem.file('/path/to/Podfile')
..createSync(recursive: true);
projectPodfile.writeAsStringSync('Standard Podfile template');
final FakeCocoaPods cocoaPods = FakeCocoaPods(podFile: projectPodfile);
final FakeFlutterProject project = FakeFlutterProject(
usesSwiftPackageManager: true,
fileSystem: fs,
fileSystem: testFileSystem,
);
final XcodeBasedProject xcodeProject =
platform == SupportedPlatform.ios ? project.ios : project.macos;
@ -269,8 +382,10 @@ void main() {
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: fs,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(isSwiftPackageManagerEnabled: true),
logger: testLogger,
analytics: testAnalytics,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isTrue);
@ -296,16 +411,36 @@ void main() {
);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isFalse);
expect(
testAnalytics.sentEvents,
contains(
Event.flutterInjectDarwinPlugins(
platform: platform.name,
isModule: false,
swiftPackageManagerUsable: true,
swiftPackageManagerFeatureEnabled: true,
projectDisabledSwiftPackageManager: false,
projectHasSwiftPackageManagerIntegration: true,
pluginCount: 1,
swiftPackageCount: 1,
podCount: 0,
),
),
);
},
);
testWithoutContext('with mixed plugins', () async {
final MemoryFileSystem fs = MemoryFileSystem();
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final File cocoapodPluginPodspec = fs.file(
final FakeAnalytics testAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final File cocoapodPluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1.podspec',
)..createSync(recursive: true);
final File swiftPackagePluginPodspec = fs.file(
final File swiftPackagePluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1/Package.swift',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
@ -328,28 +463,60 @@ void main() {
expectedPlugins: plugins,
);
final FakeCocoaPods cocoaPods = FakeCocoaPods();
final FakeFlutterProject project = FakeFlutterProject(
usesSwiftPackageManager: true,
fileSystem: testFileSystem,
);
final XcodeBasedProject xcodeProject =
platform == SupportedPlatform.ios ? project.ios : project.macos;
xcodeProject.xcodeProjectInfoFile.createSync(recursive: true);
xcodeProject.xcodeProjectInfoFile.writeAsStringSync(
'FlutterGeneratedPluginSwiftPackage',
);
final DarwinDependencyManagement dependencyManagement = DarwinDependencyManagement(
project: FakeFlutterProject(usesSwiftPackageManager: true, fileSystem: fs),
project: project,
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: fs,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(isSwiftPackageManagerEnabled: true),
logger: testLogger,
analytics: testAnalytics,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isTrue);
expect(testLogger.warningText, isEmpty);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isTrue);
expect(
testAnalytics.sentEvents,
contains(
Event.flutterInjectDarwinPlugins(
platform: platform.name,
isModule: false,
swiftPackageManagerUsable: true,
swiftPackageManagerFeatureEnabled: true,
projectDisabledSwiftPackageManager: false,
projectHasSwiftPackageManagerIntegration: true,
pluginCount: 2,
swiftPackageCount: 1,
podCount: 1,
),
),
);
});
});
group('when not using Swift Package Manager', () {
testWithoutContext('but project already migrated', () async {
final MemoryFileSystem fs = MemoryFileSystem();
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final File cocoapodPluginPodspec = fs.file(
final FakeAnalytics testAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final File cocoapodPluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1.podspec',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
@ -365,7 +532,7 @@ void main() {
final FakeCocoaPods cocoaPods = FakeCocoaPods();
final FakeFlutterProject project = FakeFlutterProject(
usesSwiftPackageManager: true,
fileSystem: fs,
fileSystem: testFileSystem,
);
final XcodeBasedProject xcodeProject =
platform == SupportedPlatform.ios ? project.ios : project.macos;
@ -379,20 +546,42 @@ void main() {
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: fs,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(isSwiftPackageManagerEnabled: true),
logger: testLogger,
analytics: testAnalytics,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isTrue);
expect(testLogger.warningText, isEmpty);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isTrue);
expect(
testAnalytics.sentEvents,
contains(
Event.flutterInjectDarwinPlugins(
platform: platform.name,
isModule: false,
swiftPackageManagerUsable: true,
swiftPackageManagerFeatureEnabled: true,
projectDisabledSwiftPackageManager: false,
projectHasSwiftPackageManagerIntegration: true,
pluginCount: 1,
swiftPackageCount: 0,
podCount: 1,
),
),
);
});
testWithoutContext('with only CocoaPod plugins', () async {
final MemoryFileSystem fs = MemoryFileSystem();
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final File cocoapodPluginPodspec = fs.file(
final FakeAnalytics testAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final File cocoapodPluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1.podspec',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
@ -408,24 +597,46 @@ void main() {
final FakeCocoaPods cocoaPods = FakeCocoaPods();
final DarwinDependencyManagement dependencyManagement = DarwinDependencyManagement(
project: FakeFlutterProject(fileSystem: fs),
project: FakeFlutterProject(fileSystem: testFileSystem),
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: fs,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(),
logger: testLogger,
analytics: testAnalytics,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isFalse);
expect(testLogger.warningText, isEmpty);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isTrue);
expect(
testAnalytics.sentEvents,
contains(
Event.flutterInjectDarwinPlugins(
platform: platform.name,
isModule: false,
swiftPackageManagerUsable: false,
swiftPackageManagerFeatureEnabled: false,
projectDisabledSwiftPackageManager: false,
projectHasSwiftPackageManagerIntegration: false,
pluginCount: 1,
swiftPackageCount: 0,
podCount: 1,
),
),
);
});
testWithoutContext('with only Swift Package Manager plugins', () async {
final MemoryFileSystem fs = MemoryFileSystem();
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final File swiftPackagePluginPodspec = fs.file(
final FakeAnalytics testAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final File swiftPackagePluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1/Package.swift',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
@ -441,12 +652,14 @@ void main() {
final FakeCocoaPods cocoaPods = FakeCocoaPods();
final DarwinDependencyManagement dependencyManagement = DarwinDependencyManagement(
project: FakeFlutterProject(fileSystem: fs),
project: FakeFlutterProject(fileSystem: testFileSystem),
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: fs,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(),
logger: testLogger,
analytics: testAnalytics,
);
await expectLater(
() => dependencyManagement.setUp(platform: platform),
@ -460,12 +673,17 @@ void main() {
);
expect(swiftPackageManager.generated, isFalse);
expect(cocoaPods.podfileSetup, isFalse);
expect(testAnalytics.sentEvents, isEmpty);
});
testWithoutContext('when project is a module', () async {
final MemoryFileSystem fs = MemoryFileSystem();
final MemoryFileSystem testFileSystem = MemoryFileSystem.test();
final BufferLogger testLogger = BufferLogger.test();
final File cocoapodPluginPodspec = fs.file(
final FakeAnalytics testAnalytics = getInitializedFakeAnalyticsInstance(
fs: testFileSystem,
fakeFlutterVersion: FakeFlutterVersion(),
);
final File cocoapodPluginPodspec = testFileSystem.file(
'/path/to/cocoapod_plugin_1/darwin/cocoapod_plugin_1.podspec',
)..createSync(recursive: true);
final List<Plugin> plugins = <Plugin>[
@ -481,18 +699,21 @@ void main() {
final FakeCocoaPods cocoaPods = FakeCocoaPods();
final DarwinDependencyManagement dependencyManagement = DarwinDependencyManagement(
project: FakeFlutterProject(fileSystem: fs, isModule: true),
project: FakeFlutterProject(fileSystem: testFileSystem, isModule: true),
plugins: plugins,
cocoapods: cocoaPods,
swiftPackageManager: swiftPackageManager,
fileSystem: fs,
fileSystem: testFileSystem,
featureFlags: TestFeatureFlags(),
logger: testLogger,
analytics: testAnalytics,
);
await dependencyManagement.setUp(platform: platform);
expect(swiftPackageManager.generated, isFalse);
expect(testLogger.warningText, isEmpty);
expect(testLogger.statusText, isEmpty);
expect(cocoaPods.podfileSetup, isFalse);
expect(testAnalytics.sentEvents, isEmpty);
});
});
});
@ -571,15 +792,24 @@ class FakeMacOSProject extends Fake implements MacOSProject {
File xcodeConfigFor(String mode) => managedDirectory.childFile('Flutter-$mode.xcconfig');
}
class FakeFlutterManifest extends Fake implements FlutterManifest {
FakeFlutterManifest({this.disabledSwiftPackageManager = false});
@override
final bool disabledSwiftPackageManager;
}
class FakeFlutterProject extends Fake implements FlutterProject {
FakeFlutterProject({
required this.fileSystem,
this.usesSwiftPackageManager = false,
this.isModule = false,
});
FlutterManifest? manifest,
}) : _manifest = manifest ?? FakeFlutterManifest();
final MemoryFileSystem fileSystem;
final bool usesSwiftPackageManager;
final FlutterManifest _manifest;
@override
late final FakeIosProject ios = FakeIosProject(
@ -595,6 +825,9 @@ class FakeFlutterProject extends Fake implements FlutterProject {
@override
final bool isModule;
@override
FlutterManifest get manifest => _manifest;
}
class FakeSwiftPackageManager extends Fake implements SwiftPackageManager {