Adding Swift Package Manager Support to a Flutter Plugin Without Breaking CocoaPods
CocoaPods enters read-only maintenance in December 2026, and Flutter 3.44 already defaults to SPM. A plugin without a Package.swift is invisible to any project that has switched over, which will soon be the majority. This walkthrough shows how to add SPM support as a non-breaking addition—existing CocoaPods users see zero change—while avoiding the silent fallback trap that makes you think SPM works when it doesn't.
From Flutter 3.44 onward, Swift Package Manager is the default dependency mechanism for iOS plugins, and the CocoaPods trunk goes read-only in December 2026. Plugins that lack a Package.swift simply disappear for pure-SPM projects. The fix is not to replace the podspec but to add a Package.swift alongside it, pointing both at the same source files and the same pre-compiled xcframework.
The migration moves source code into the Sources/<target>/ layout that SPM requires, updates the podspec's source_files to match, and adds a binaryTarget that fetches the identical GitHub Release zip that CocoaPods already downloads via prepare_command. A FlutterFramework dependency, injected by the Flutter tool at build time, supplies the Flutter module import—but only exists in Flutter 3.44+, which sets the hard minimum version for SPM users.
Verification is the trickiest part: Flutter's fallback logic silently routes through CocoaPods if anything is missing, so the only reliable test is checking whether the plugin appears in Podfile.lock. The final checklist covers eight concrete steps, from moving source files to aligning minimum iOS versions and ignoring SPM build artifacts.
Flutter's silent fallback from SPM to CocoaPods is the biggest footgun in this migration—a plugin can compile fine in testing while never actually exercising the new SPM path, giving false confidence.
The FlutterFramework dependency that makes SPM work is also what locks the plugin to Flutter 3.44+, creating a hard version split: SPM users must be on the latest Flutter, while CocoaPods users face no such constraint.
Keeping the podspec and Package.swift pointed at the same binary artifact turns a potential fork into a single-source setup, but it also creates a release-process hazard—every xcframework update must touch both files or the two user populations diverge silently.