Since Flutter 3.44 turned Swift Package Manager on by default, what must a Flutter plugin ship for iOS and macOS, and what happens to plugins with only a podspec?
answer
- 3.44 flips the default
- ios/<name>/Package.swift plus Sources
- depends on the FlutterFramework package
- keep the podspec for unmigrated apps
- per-project opt-out in pubspec config
basics
~20 sA plugin should ship a Swift package (Package.swift with a Sources folder under ios, macos or darwin) and keep its podspec. Apps fall back to CocoaPods for plugins lacking Swift Package Manager support, which keeps them working but mixes two dependency managers.
solid answer
~40 sAs of Flutter 3.44, Swift Package Manager (SwiftPM) manages iOS and macOS native dependencies by default and CocoaPods is in maintenance mode. A plugin adds `ios/<plugin_name>/Package.swift` with `Sources/<plugin_name>/` (or the same under `macos/` or `darwin/`), declaring its supported platforms, a library product, and a dependency on the `FlutterFramework` package at `../FlutterFramework`; resources such as `PrivacyInfo.xcprivacy` go in the target's `resources`. The docs ask plugins to support **both** SwiftPM and CocoaPods for now, because projects that have not migrated still use CocoaPods. For plugins with only a podspec, Flutter falls back to CocoaPods in the same app, which works but can cause duplicate-module build errors. A project can turn SwiftPM off with `enable-swift-package-manager: false` under `flutter: config:` in pubspec.yaml.
code
yaml · 4 lines# pubspec.yaml of an app that must stay on CocoaPods for now
flutter:
config:
enable-swift-package-manager: falsego deeper
Remember that Flutter 3.44 made Swift Package Manager the default for iOS and macOS plugins while CocoaPods still works as a fallback.
Explain the Package.swift layout under ios, macos or darwin, the FlutterFramework dependency, and why the podspec stays for unmigrated apps.
Diagnose mixed-manager build failures such as duplicate modules or minimum-platform mismatches and plan when an app can drop CocoaPods.
Schedule migration across your plugins and apps against the CocoaPods registry going read-only, weighing forks of unmigrated third-party plugins.
## What changed and when Two dependency managers can pull native code into a Flutter iOS or macOS app: - **CocoaPods** — a Ruby-based dependency manager that reads a plugin's `.podspec` and a `Podfile` in the app. - **Swift Package Manager (SwiftPM)** — Apple's package manager, driven by a `Package.swift` manifest and integrated into Xcode. As of **Flutter 3.44**, SwiftPM support is **on by default**. Running an app on 3.44 or later automatically adds SwiftPM integration to the Xcode project (a generated `FlutterGeneratedPluginSwiftPackage` dependency and a "Run Prepare Flutter Framework Script" pre-action). Flutter keeps supporting CocoaPods in **maintenance mode**, and the Flutter docs note that the CocoaPods registry becomes read-only on 2 December 2026. ## What a plugin ships For each Apple platform folder (`ios/`, `macos/`, or the shared `darwin/` when `sharedDarwinSource: true`): 1. a directory named after the plugin, e.g. `ios/thermo/`; 2. inside it, `Package.swift` and `Sources/thermo/` holding the Swift or Objective-C sources; 3. a manifest that declares supported platforms, a library product and a dependency on `FlutterFramework`. ```swift // swift-tools-version: 5.9 import PackageDescription let package = Package( name: "thermo", platforms: [.iOS("13.0")], products: [.library(name: "thermo", targets: ["thermo"])], dependencies: [ .package(name: "FlutterFramework", path: "../FlutterFramework") ], targets: [ .target( name: "thermo", dependencies: [.product(name: "FlutterFramework", package: "FlutterFramework")], resources: [.process("PrivacyInfo.xcprivacy")] ) ] ) ``` - The library name replaces `_` with `-` when the plugin name contains underscores. - Resources such as a privacy manifest or bundled files must be listed in `resources`; they are not picked up implicitly. - The **podspec stays**: the docs say plugins should support both managers until further notice, because apps that have not migrated (or turned SwiftPM off) still resolve through CocoaPods. A plugin with only `Package.swift` is unusable by those apps. ## What happens to a podspec-only plugin | App setup | Plugin supports | Result | |---|---|---| | SwiftPM on | SwiftPM and CocoaPods | Resolved through SwiftPM | | SwiftPM on | CocoaPods only | Flutter **falls back to CocoaPods** for that plugin | | SwiftPM off | CocoaPods only or both | Resolved through CocoaPods | | SwiftPM off | SwiftPM only | Build fails; the tool suggests `flutter config --enable-swift-package-manager` | The fallback keeps apps building, but the project now uses **both** managers. If the same module arrives through a pod and a Swift package, Xcode reports duplicate modules, and the Flutter tool points at the mix as the likely cause. A CocoaPods integration can be removed from the app only once every plugin supports SwiftPM. ## Turning it off - Per project: in `pubspec.yaml`, `flutter: config: enable-swift-package-manager: false` — applies to every contributor. - Per user: `flutter config --no-enable-swift-package-manager`. The docs advise against both, because the CocoaPods registry is going read-only and disabling SwiftPM is expected to stop being allowed. ## Other migration traps - A plugin whose `Package.swift` requires a newer minimum OS than the app fails with a minimum-platform-version error; raise the app's Minimum Deployments in Xcode, then run `flutter build ios --config-only` to regenerate configuration. - Native XCTests in a plugin's example app that used a CocoaPods test dependency must add it as a Swift package to the test target instead. - A plugin declared `type: .dynamic` needs extra linking for tests; Apple recommends leaving the library type automatic.
- Why should a plugin keep its podspec after adding Package.swift?Apps that have not migrated, or that turned SwiftPM off, still resolve native code through CocoaPods. A SwiftPM-only plugin is unusable for them, so the docs ask plugins to support both managers until further notice.
- An app on 3.47 fails with a duplicate-module error after upgrading. What is the likely cause?The project now uses both CocoaPods and SwiftPM, and one module arrives through both — typically a podspec-only plugin pulling a pod that another plugin brings as a Swift package. Check `Podfile.lock` for the module and ask the pod's plugin author for SwiftPM support.
saying these in an interview costs you the question
- Flutter 3.47 no longer supports CocoaPods at all.
- A plugin can drop its podspec as soon as it adds Package.swift.
- A podspec-only plugin cannot be used in a SwiftPM-enabled app.
- Resources are bundled automatically without listing them in Package.swift.
- SwiftPM changes how Dart code in the plugin is compiled.