git:20260318.896ce92 to git:20260501.ed3e92e

163 added, 282 removed. Audit B to A.

---
name: cocoapods-to-spm
- description: Guide to migrating iOS Capacitor plugins and dependencies from CocoaPods to Swift Package Manager (SPM). Use this skill when users want to modernize their iOS project, remove CocoaPods, or add SPM-based dependencies.
+ description: Guide to migrating an existing Capacitor iOS app from CocoaPods to Swift Package Manager (SPM). Use this skill when users want Capacitor 8-style SPM projects, need to run or recover from spm-migration-assistant, replace Podfile/Pods/App.xcworkspace with CapApp-SPM, add debug.xcconfig, verify plugin SPM support, or remove CocoaPods from an app project.
---
# CocoaPods to Swift Package Manager Migration
- Step-by-step guide for migrating Capacitor iOS projects from CocoaPods to Swift Package Manager.
+ Migrate a Capacitor iOS app from CocoaPods to Swift Package Manager without losing native project customizations.
## When to Use This Skill
- - User wants to migrate from CocoaPods to SPM
- - User is setting up a new project with SPM
- - User needs to add SPM dependencies to Capacitor
- - User has CocoaPods issues and wants an alternative
- - User wants faster builds (SPM often faster)
+ - User wants to migrate a Capacitor app from CocoaPods to SPM
+ - User asks about `npx cap spm-migration-assistant`
+ - User asks about `CapApp-SPM`, generated `Package.swift`, or `debug.xcconfig`
+ - User has Capacitor 8 and wants the iOS app to use the default SPM template
+ - User wants to remove `ios/App/Podfile`, `Pods`, `Podfile.lock`, or `App.xcworkspace`
+ - User has SPM migration errors caused by plugins without SPM support
- ## Why Migrate to SPM?
+ Do not use this for adding SPM support to a plugin package. Use `capacitor-plugin-spm-support` for plugin repositories.
- | Aspect | CocoaPods | SPM |
- |--------|-----------|-----|
- | Build Speed | Slower | Faster |
- | Apple Integration | Third-party | Native Xcode |
- | Ruby Dependency | Required | None |
- | Version Management | Podfile.lock | Package.resolved |
- | Xcodeproj Changes | Modifies project | Uses workspace |
- | Binary Caching | Limited | Built-in |
+ ## Key Rules
- ## Migration Process
+ - Capacitor 8 creates new iOS projects with SPM by default.
+ - Existing CocoaPods apps are not changed automatically just because Capacitor is upgraded.
+ - In an SPM-based Capacitor app, plugin dependencies are referenced through `ios/App/CapApp-SPM`.
+ - Do not edit `CapApp-SPM` by hand. The Capacitor CLI rewrites it during `npx cap sync`.
+ - Do not mix CocoaPods and SPM in the same Capacitor app migration. All Capacitor and Cordova plugins in `package.json` need SPM support before the app can fully move.
+ - Commit or otherwise preserve the current project before deleting, regenerating, or deintegrating the iOS project.
- ### Step 1: Analyze Current Dependencies
+ ## Command Policy
- First, identify what you're currently using:
+ - Use the target repo's package manager for dependency installs and package scripts.
+ - For Capacitor CLI commands in this skill, use `npx cap ...` so the project-local Capacitor CLI is used.
+ - In Capgo repos, use Bun for local development commands when repo instructions require it, but keep Capacitor CLI examples as `npx cap ...`.
- ```bash
- cd ios/App
- cat Podfile
- pod outdated
- ```
+ ## Live Project Snapshot
- Common Capacitor pods to migrate:
- ```ruby
- # Podfile (before)
- target 'App' do
- capacitor_pods
- pod 'Firebase/Analytics'
- pod 'Firebase/Messaging'
- pod 'Alamofire'
- pod 'KeychainAccess'
- end
- ```
+ Detected Capacitor, iOS, Cordova, and plugin dependencies:
+ !`node -e "const fs=require('fs');if(!fs.existsSync('package.json'))process.exit(0);const pkg=JSON.parse(fs.readFileSync('package.json','utf8'));const out=[];for(const section of ['dependencies','devDependencies']){for(const [name,version] of Object.entries(pkg[section]||{})){if(name.startsWith('@capacitor/')||name.startsWith('@capgo/')||name.startsWith('@capacitor-community/')||name.startsWith('@awesome-cordova-plugins/')||name.startsWith('cordova-')||name.includes('capacitor'))out.push(section+'.'+name+'='+version)}}console.log(out.sort().join('\n'))"`
- ### Step 2: Find SPM Equivalents
+ Relevant iOS dependency files:
+ !`find ios -maxdepth 5 \( -name 'Podfile' -o -name 'Podfile.lock' -o -name 'Pods' -o -name 'App.xcworkspace' -o -name 'Package.swift' -o -name 'Package.resolved' -o -name 'CapApp-SPM' -o -name 'debug.xcconfig' -o -name 'project.pbxproj' -o -name 'Info.plist' -o -name '*.entitlements' -o -name 'GoogleService-Info.plist' \) 2>/dev/null`
- Most popular libraries support SPM. Use these URLs:
+ ## Migration Procedure
- | Library | SPM URL |
- |---------|---------|
- | Firebase | `https://github.com/firebase/firebase-ios-sdk` |
- | Alamofire | `https://github.com/Alamofire/Alamofire` |
- | KeychainAccess | `https://github.com/kishikawakatsumi/KeychainAccess` |
- | SDWebImage | `https://github.com/SDWebImage/SDWebImage` |
- | SnapKit | `https://github.com/SnapKit/SnapKit` |
- | Realm | `https://github.com/realm/realm-swift` |
- | Lottie | `https://github.com/airbnb/lottie-spm` |
+ ### Step 1: Confirm Scope and Prerequisites
- ### Step 3: Clean CocoaPods
+ Inspect:
- ```bash
- cd ios/App
+ - `package.json` for Capacitor major version and installed plugins
+ - `ios/App/Podfile` and `ios/App/Podfile.lock` for current CocoaPods dependencies
+ - `ios/App/App.xcodeproj/project.pbxproj` for custom build settings, package references, entitlements, signing, and native source files
+ - `ios/App/App/` for app customizations
- # Remove CocoaPods integration
- pod deintegrate
+ Before changing files, verify:
- # Remove Podfile.lock and Pods directory
- rm -rf Podfile.lock Pods
+ - The app is on a Capacitor version that supports SPM migration.
+ - The working tree is clean or the user accepts that local changes are being preserved.
+ - Every Capacitor/Cordova plugin has SPM support or a replacement plan.
- # Remove workspace (we'll use project directly or create new workspace)
- rm -rf App.xcworkspace
- ```
+ If the migration is part of a Capacitor 8 upgrade, combine this skill with `capacitor-app-upgrade-v7-to-v8`.
- ### Step 4: Add SPM Dependencies in Xcode
+ ### Step 2: Preserve Native Customizations
- 1. Open `ios/App/App.xcodeproj` in Xcode
- 2. Select the project in navigator
- 3. Go to **Package Dependencies** tab
- 4. Click **+** to add package
- 5. Enter the package URL
- 6. Choose version rules
- 7. Select target `App`
+ Record and preserve anything under `ios/` that a fresh template would overwrite:
- ### Step 5: Update Podfile for Capacitor Core
+ - `ios/App/App/Info.plist`
+ - `ios/App/App/AppDelegate.swift`
+ - `ios/App/App/SceneDelegate.swift`, if present
+ - `ios/App/App/Assets.xcassets/`
+ - `ios/App/App/Base.lproj/`
+ - `ios/App/App/*.entitlements`
+ - `ios/App/App/GoogleService-Info.plist`, if Firebase is used
+ - custom `.xcconfig` files
+ - custom Swift or Objective-C source files
+ - custom frameworks, SDK files, extension targets, build phases, schemes, and signing settings
- Capacitor still needs CocoaPods for its core. Create minimal Podfile:
+ Prefer preserving through git and explicit diffs. Do not rely on memory.
- ```ruby
- # ios/App/Podfile
- require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
+ ### Step 3: Choose the Migration Path
- platform :ios, '14.0'
- use_frameworks!
+ Use the safest path for the project:
- install! 'cocoapods', :disable_input_output_paths => true
+ | Path | Use When | Tradeoff |
+ |------|----------|----------|
+ | CLI assistant | The iOS project has moderate customization and plugins mostly support SPM | Automates CocoaPods removal but still needs Xcode steps |
+ | Fresh SPM re-scaffold | The iOS project is close to the Capacitor template | Cleanest result, but native customizations must be restored carefully |
+ | Manual repair | The assistant already ran or the project is heavily customized | More control, more Xcode project editing |
- def capacitor_pods
- pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
- pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
- end
+ If unsure, start with plugin compatibility and backup work. Do not delete `ios/` until the preservation list is complete.
- target 'App' do
- capacitor_pods
- # Other plugin pods that don't support SPM yet
- end
+ ### Step 4: Run the CLI Assistant
- post_install do |installer|
- assertDeploymentTarget(installer)
- end
- ```
+ Preferred first attempt for many existing apps:
- Then run:
```bash
- cd ios/App && pod install
+ npx cap spm-migration-assistant
```
- ### Step 6: Configure Plugin for SPM Support
+ Expect it to:
- If you're creating a Capacitor plugin with SPM support:
+ - run CocoaPods deintegration
+ - remove `Podfile`, `Podfile.lock`, `Pods`, and `App.xcworkspace`
+ - create `ios/App/CapApp-SPM`
+ - generate a `Package.swift` from installed plugins
+ - generate `debug.xcconfig`
+ - warn about plugins that cannot be represented as SPM packages
- **Package.swift**:
- ```swift
- // swift-tools-version: 5.9
- import PackageDescription
+ Then open the iOS project:
- let package = Package(
- name: "CapacitorNativeBiometric",
- platforms: [.iOS(.v14)],
- products: [
- .library(
- name: "CapacitorNativeBiometric",
- targets: ["NativeBiometricPlugin"]
- ),
- ],
- dependencies: [
- .package(url: "https://github.com/nicholasalx/capacitor-swift-pm", from: "6.0.0"),
- ],
- targets: [
- .target(
- name: "NativeBiometricPlugin",
- dependencies: [
- .product(name: "Capacitor", package: "capacitor-swift-pm"),
- .product(name: "Cordova", package: "capacitor-swift-pm"),
- ],
- path: "ios/Sources/NativeBiometricPlugin",
- publicHeadersPath: "include"
- ),
- ]
- )
+ ```bash
+ npx cap open ios
```
- ### Step 7: Xcode Project Structure for SPM
+ In Xcode:
- ```
- ios/
- ├── App/
- │ ├── App/
- │ │ ├── AppDelegate.swift
- │ │ ├── Info.plist
- │ │ └── ...
- │ ├── App.xcodeproj/
- │ │ └── project.xcworkspace/
- │ │ └── xcshareddata/
- │ │ └── swiftpm/
- │ │ └── Package.resolved # SPM lock file
- │ ├── Podfile
- │ └── Podfile.lock
- └── ...
- ```
+ - Select the app project.
+ - Open the Package Dependencies tab.
+ - Add the local `CapApp-SPM` package.
+ - Add the generated `debug.xcconfig` to the project configuration as directed by the assistant output.
- ## Hybrid Approach (Recommended)
+ After Xcode changes, run:
- Most Capacitor projects work best with a hybrid approach:
+ ```bash
+ npx cap sync ios
+ ```
- ### Keep in CocoaPods:
- - `@capacitor/ios` core
- - Capacitor plugins without SPM support
+ ### Step 5: Fresh Re-Scaffold Alternative
- ### Move to SPM:
- - Firebase
- - Third-party libraries
- - Your own Swift packages
+ Use this when the iOS project has little or no custom native configuration, or the assistant path is messier than regenerating.
- ### Example Hybrid Setup
+ Before deleting anything, preserve the native files listed in Step 2.
- **Podfile**:
- ```ruby
- require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
+ Then re-create iOS with SPM:
- platform :ios, '14.0'
- use_frameworks!
+ ```bash
+ rm -rf ios
+ npx cap add ios --packagemanager SPM
+ npx cap sync ios
+ ```
- install! 'cocoapods', :disable_input_output_paths => true
+ For Capacitor 8+, `npx cap add ios` uses SPM by default, but keep `--packagemanager SPM` when documenting the migration so the intent is explicit.
- def capacitor_pods
- pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
- pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
- # Plugins without SPM support
- pod 'CapacitorCamera', :path => '../../node_modules/@capacitor/camera'
- end
+ Restore custom files and settings deliberately:
- target 'App' do
- capacitor_pods
- # NO Firebase here - use SPM instead
- end
- ```
+ - copy back app icons and launch storyboards
+ - reapply `Info.plist` keys without overwriting new template changes blindly
+ - restore entitlements and signing
+ - restore Firebase or other service configuration files
+ - re-add custom native source, extensions, build phases, and schemes
- **Xcode Package Dependencies**:
- - Firebase iOS SDK
- - Any other SPM-compatible libraries
+ ### Step 6: Fix Plugin Compatibility
- ## Common Issues and Solutions
+ If `npx cap sync` or the assistant warns about unsupported plugins:
- ### Issue: Duplicate Symbols
+ - upgrade the plugin to an SPM-capable version
+ - replace the plugin with an official, Capgo, or maintained community alternative
+ - migrate the plugin itself with `capacitor-plugin-spm-support` if it is owned by the project
+ - postpone full SPM migration if a critical plugin cannot support SPM yet
- **Cause**: Same library in both CocoaPods and SPM
+ Do not keep a plugin in CocoaPods while the app is otherwise migrated to SPM.
- **Solution**: Remove from Podfile if using SPM
- ```ruby
- # Podfile - WRONG
- pod 'Firebase/Analytics' # Remove this
+ ### Step 7: Validate the New iOS Project
- # Use SPM instead in Xcode
+ Run the repo's normal web build first, then sync and build iOS:
+
+ ```bash
+ npx cap sync ios
+ npx cap open ios
```
- ### Issue: Module Not Found
+ In Xcode, verify:
- **Cause**: SPM package not linked to target
+ - `CapApp-SPM` is present as a local package dependency
+ - `debug.xcconfig` is attached to the debug configuration
+ - `Podfile`, `Pods`, `Podfile.lock`, and `App.xcworkspace` are gone for the migrated app
+ - `Package.resolved` is generated and committed if present
+ - signing team, bundle identifier, deployment target, entitlements, and capabilities survived
+ - app builds and launches on simulator
+ - native plugin flows still work on a real device when they need hardware or permissions
- **Solution**:
- 1. Xcode > Project > Targets > App
- 2. General > Frameworks, Libraries, and Embedded Content
- 3. Add the SPM package product
+ If using command-line verification, use the workspace/project and scheme that actually exist after migration.
- ### Issue: Build Errors After Migration
+ ## Common Failures
- **Cause**: Missing frameworks or wrong imports
+ ### Unsupported Plugin
- **Solution**: Clean and rebuild
- ```bash
- # Clean derived data
- rm -rf ~/Library/Developer/Xcode/DerivedData
+ Cause: a Capacitor or Cordova plugin does not ship SPM metadata.
- # Clean build folder in Xcode
- # Cmd + Shift + K
+ Fix: upgrade, replace, or migrate the plugin. If the plugin is project-owned, use `capacitor-plugin-spm-support`.
- # Rebuild
+ ### Missing `CapApp-SPM`
+
+ Cause: the assistant did not finish, files were deleted, or `npx cap sync` has not regenerated the package.
+
+ Fix:
+
+ ```bash
npx cap sync ios
- cd ios/App && pod install
```
- ### Issue: Capacitor Plugin Not Found
+ Then add the local package in Xcode if it is not already linked.
- **Cause**: Plugin needs registration
+ ### Missing `debug.xcconfig`
- **Solution**: Ensure plugin is registered in `AppDelegate.swift`:
- ```swift
- import Capacitor
- import YourPlugin
+ Cause: generated config was not added to the Xcode project.
- @UIApplicationMain
- class AppDelegate: UIResponder, UIApplicationDelegate {
- func application(
- _ application: UIApplication,
- didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
- ) -> Bool {
- // Capacitor handles plugin registration automatically
- return true
- }
- }
- ```
+ Fix: add `ios/App/debug.xcconfig` to the project configuration in Xcode, following the migration assistant output.
- ## Creating SPM-Compatible Capacitor Plugin
+ ### Duplicate Symbols or Duplicate SDKs
- ### Directory Structure
+ Cause: the same dependency is still referenced by leftover CocoaPods artifacts and SPM.
- ```
- my-capacitor-plugin/
- ├── Package.swift
- ├── ios/
- │ └── Sources/
- │ └── MyPlugin/
- │ ├── MyPlugin.swift
- │ ├── MyPlugin.m # Objc bridge if needed
- │ └── include/
- │ └── MyPlugin.h # Public headers
- ├── src/
- │ ├── index.ts
- │ ├── definitions.ts
- │ └── web.ts
- └── package.json
- ```
+ Fix: remove CocoaPods artifacts from the app, clean derived data, reset package caches in Xcode, and rebuild.
- ### Package.swift Template
+ ### Lost Native Customization
- ```swift
- // swift-tools-version: 5.9
- import PackageDescription
+ Cause: a fresh iOS scaffold overwrote customized files.
- let package = Package(
- name: "CapacitorMyPlugin",
- platforms: [.iOS(.v14)],
- products: [
- .library(
- name: "CapacitorMyPlugin",
- targets: ["MyPluginPlugin"]
- ),
- ],
- dependencies: [
- .package(url: "https://github.com/nicholasalx/capacitor-swift-pm", from: "6.0.0"),
- ],
- targets: [
- .target(
- name: "MyPluginPlugin",
- dependencies: [
- .product(name: "Capacitor", package: "capacitor-swift-pm"),
- .product(name: "Cordova", package: "capacitor-swift-pm"),
- ],
- path: "ios/Sources/MyPlugin"
- ),
- ]
- )
- ```
+ Fix: recover from git or the preserved backup list, then reapply changes selectively against the new SPM template.
- ### Plugin Swift Code
+ ## Output Format
- ```swift
- import Foundation
- import Capacitor
+ For planning tasks, return:
- @objc(MyPlugin)
- public class MyPlugin: CAPPlugin, CAPBridgedPlugin {
- public let identifier = "MyPlugin"
- public let jsName = "MyPlugin"
- public let pluginMethods: [CAPPluginMethod] = [
- CAPPluginMethod(name: "echo", returnType: CAPPluginReturnPromise),
- ]
+ ```markdown
+ ## SPM Migration Plan
- @objc func echo(_ call: CAPPluginCall) {
- let value = call.getString("value") ?? ""
- call.resolve(["value": value])
- }
- }
- ```
+ ### Current State
+ - Capacitor version:
+ - CocoaPods files:
+ - Plugins needing SPM check:
+ - Native customizations to preserve:
- ## Migration Checklist
+ ### Recommended Path
+ - CLI assistant / fresh re-scaffold / manual repair:
+ - Reason:
- - [ ] List all current CocoaPods dependencies
- - [ ] Identify SPM equivalents for each
- - [ ] Run `pod deintegrate`
- - [ ] Add SPM packages in Xcode
- - [ ] Create minimal Podfile for Capacitor core
- - [ ] Run `pod install`
- - [ ] Clean derived data
- - [ ] Build and test
- - [ ] Commit `Package.resolved` to git
- - [ ] Update CI/CD scripts if needed
+ ### Steps
+ 1. Preserve native files
+ 2. Verify plugin SPM support
+ 3. Run migration
+ 4. Complete Xcode package/config setup
+ 5. Sync and build
- ## Resources
+ ### Risks
+ - Unsupported plugins:
+ - Native customizations:
+ - Manual Xcode steps:
+ ```
- - Swift Package Manager Documentation: https://swift.org/package-manager
- - Capacitor iOS Documentation: https://capacitorjs.com/docs/ios
- - CocoaPods to SPM Migration: https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app
+ For implementation tasks, make the migration changes, run the relevant build or verification command available in the repo, and report any remaining Xcode-only or device-only checks.