Overview
Migrate your Userpilot Capacitor iOS app from CocoaPods to Swift Package Manager (SPM). Follow these steps for apps that still use CocoaPods, including older copies of the Userpilot Capacitor example. Capacitor 8 uses SPM by default for new iOS projects and continues to support existing CocoaPods projects. Upgrading Capacitor or runningnpx cap sync ios does not migrate an existing CocoaPods project. See Capacitor’s version 8 upgrade guide.
@userpilot/capacitor supports both dependency managers on Capacitor 6, 7, and 8. The steps below target a Capacitor 8 app.
Run commands from your app directory (example-app/ in the Userpilot Capacitor repository).
Use cases
- Migrate an existing CocoaPods app while preserving its native configuration.
- Set up a new Capacitor 8 iOS project with SPM and the Userpilot plugin.
Check your current setup
For the standard Capacitor iOS directory layout:
Capacitor detects SPM from the
CapApp-SPM directory. There is no Userpilot configuration flag to switch dependency managers. If your app already uses SPM, skip the migration and follow Verify the integration.
Before migrating
- Save a restorable copy of your iOS project, including uncommitted changes, signing settings, capabilities, URL schemes, custom native code, and extension targets.
- Ensure your Capacitor 8 environment meets its requirements: Node.js 22+, Xcode 26+, and an app deployment target of iOS 15+. Keep
@capacitor/core,@capacitor/cli, and@capacitor/ioson compatible versions. See the Capacitor 8 upgrade guide. - Install your app’s npm dependencies and install Userpilot if you have not already. The repository’s example already declares Userpilot as a local dependency.
- Check SPM support for every installed Capacitor plugin. Userpilot supports SPM, but another plugin may require an update or replacement. Capacitor does not automatically fall back to CocoaPods for incompatible plugins. Cordova plugins also need to be checked individually.
- Review custom pods,
Podfilehooks, build settings, and dependencies belonging to app extensions. Arrange their SPM equivalents and preserve any custom setup before the assistant removes CocoaPods integration. Keep CocoaPods available to runpod deintegrateduring migration.
Migrate an existing CocoaPods app
Build your web assets, then run Capacitor’s migration assistant:pod deintegrate, removes ios/App/Podfile, Podfile.lock, and App.xcworkspace, and creates ios/App/CapApp-SPM/ and ios/debug.xcconfig. It generates package dependencies from your installed plugins and reports incompatible plugins. Resolve those warnings before continuing; custom pod dependencies and hooks need your own migration work.
Complete the Xcode setup
App.xcodeproj; the CocoaPods workspace has been removed.
- Select the App project, then Package Dependencies, and click +.
- Choose Add Local…, select
ios/App/CapApp-SPM, and add the package. - Add its CapApp-SPM library product to your App target. Confirm it appears in the target’s Frameworks, Libraries, and Embedded Content.
- Under the project’s Info > Configurations, add
ios/debug.xcconfigand use it for the app’s Debug configuration. If you already use a custom Debug xcconfig, retain it and include the generated file using the correct relative path. - Restore any custom build settings or scripts previously supplied by your
Podfile, and add any separately managed native or extension dependencies to their intended targets.
Use SPM in a new iOS project
For a Capacitor 8 app that does not yet have an iOS project:Verify the integration
From the app directory:ios/App/CapApp-SPM/Package.swiftincludes theUserpilotCapacitorpackage and product.- Xcode resolves the native
Userpilotdependency through the plugin’s package. - The app builds and launches on an iOS simulator or device, and your existing Userpilot initialization and tracking calls work.
CapApp-SPM/Package.swift during sync, so avoid editing that generated file manually. Your Userpilot JavaScript initialization and API calls remain the same.
Troubleshooting
- A plugin is missing from the generated package: check the sync output for SPM compatibility warnings and install a compatible plugin version before syncing again.
- Xcode cannot resolve a package: confirm that
CapApp-SPMis linked to the app target and runnpx cap sync ios. If resolution remains stale, use File > Packages > Reset Package Caches, then resolve the packages again. - Duplicate Userpilot dependencies or symbols: remove any extra manual Userpilot installation left in the app and keep the dependency supplied by the Capacitor plugin.
- A custom native dependency is missing: migrate the dependency and its build settings from your saved
Podfile, including any separate extension targets.
Going back to CocoaPods
Restore the migration-related iOS project changes from your saved copy, including the originalPodfile, Podfile.lock, workspace, Xcode project, and custom configuration. Preserve unrelated work. Remove the generated CapApp-SPM directory and ios/debug.xcconfig if they did not exist before migration; leaving CapApp-SPM in place makes Capacitor continue selecting SPM.
Then reinstall the CocoaPods dependencies and open the restored workspace:
npx cap add ios --packagemanager CocoaPods. This command does not convert an existing SPM project.
References
- Swift Package Manager in Capacitor
- Updating to Capacitor 8
- Userpilot Capacitor package manifest
- Userpilot Capacitor CocoaPods specification
FAQs
Do I need to change my Userpilot JavaScript calls?
Do I need to change my Userpilot JavaScript calls?
Your initialization and tracking calls remain the same. SPM changes how
your iOS app installs the native dependencies.
Can I install the native Userpilot package separately?
Can I install the native Userpilot package separately?
Keep the native SDK dependency supplied by the Capacitor plugin. Adding
another copy to the app target can cause duplicate dependencies or symbols.