Skip to main content

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 running npx 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/ios on 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, Podfile hooks, 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 run pod deintegrate during migration.

Migrate an existing CocoaPods app

Build your web assets, then run Capacitor’s migration assistant:
The assistant runs 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

After migration, use App.xcodeproj; the CocoaPods workspace has been removed.
  1. Select the App project, then Package Dependencies, and click +.
  2. Choose Add Local…, select ios/App/CapApp-SPM, and add the package.
  3. Add its CapApp-SPM library product to your App target. Confirm it appears in the target’s Frameworks, Libraries, and Embedded Content.
  4. Under the project’s Info > Configurations, add ios/debug.xcconfig and 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.
  5. 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.
See Capacitor’s illustrated migration steps for the package and configuration dialogs.

Use SPM in a new iOS project

For a Capacitor 8 app that does not yet have an iOS project:
The SPM template already includes the package and Debug configuration. Use the migration steps above for an existing iOS project so you preserve its native configuration.

Verify the integration

From the app directory:
Confirm that:
  • ios/App/CapApp-SPM/Package.swift includes the UserpilotCapacitor package and product.
  • Xcode resolves the native Userpilot dependency 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.
The dependency chain is:
Do not add the native Userpilot SDK separately to the app target. The plugin’s Package.swift selects its version. Capacitor regenerates 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-SPM is linked to the app target and run npx 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 original Podfile, 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:
For a new iOS project, you can explicitly choose CocoaPods with npx cap add ios --packagemanager CocoaPods. This command does not convert an existing SPM project.

References

FAQs

Your initialization and tracking calls remain the same. SPM changes how your iOS app installs the native dependencies.
Keep the native SDK dependency supplied by the Capacitor plugin. Adding another copy to the app target can cause duplicate dependencies or symbols.