cocoapods-to-spm

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

CocoaPods to Swift Package Manager Migration

从CocoaPods迁移至Swift Package Manager(SPM)

Step-by-step guide for migrating Capacitor iOS projects from CocoaPods to Swift Package Manager.
为Capacitor iOS项目从CocoaPods迁移至Swift Package Manager提供的分步指南。

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)
  • 用户希望从CocoaPods迁移至SPM
  • 用户正在使用SPM搭建新项目
  • 用户需要为Capacitor添加SPM依赖项
  • 用户遇到CocoaPods问题,想要寻找替代方案
  • 用户希望提升构建速度(SPM通常速度更快)

Why Migrate to SPM?

为何迁移至SPM?

AspectCocoaPodsSPM
Build SpeedSlowerFaster
Apple IntegrationThird-partyNative Xcode
Ruby DependencyRequiredNone
Version ManagementPodfile.lockPackage.resolved
Xcodeproj ChangesModifies projectUses workspace
Binary CachingLimitedBuilt-in
维度CocoaPodsSPM
构建速度较慢更快
Apple集成第三方工具Xcode原生支持
Ruby依赖必需
版本管理Podfile.lockPackage.resolved
Xcodeproj变更修改项目文件使用工作区
二进制缓存受限内置支持

Migration Process

迁移流程

Step 1: Analyze Current Dependencies

步骤1:分析当前依赖项

First, identify what you're currently using:
bash
cd ios/App
cat Podfile
pod outdated
Common Capacitor pods to migrate:
ruby
undefined
首先,确认当前使用的依赖:
bash
cd ios/App
cat Podfile
pod outdated
常见需迁移的Capacitor Pods:
ruby
undefined

Podfile (before)

Podfile (before)

target 'App' do capacitor_pods pod 'Firebase/Analytics' pod 'Firebase/Messaging' pod 'Alamofire' pod 'KeychainAccess' end
undefined
target 'App' do capacitor_pods pod 'Firebase/Analytics' pod 'Firebase/Messaging' pod 'Alamofire' pod 'KeychainAccess' end
undefined

Step 2: Find SPM Equivalents

步骤2:寻找SPM替代方案

Most popular libraries support SPM. Use these URLs:
LibrarySPM 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
大多数热门库都支持SPM。可使用以下URL:
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 3: Clean CocoaPods

步骤3:清理CocoaPods

bash
cd ios/App
bash
cd ios/App

Remove CocoaPods integration

移除CocoaPods集成

pod deintegrate
pod deintegrate

Remove Podfile.lock and Pods directory

移除Podfile.lock和Pods目录

rm -rf Podfile.lock Pods
rm -rf Podfile.lock Pods

Remove workspace (we'll use project directly or create new workspace)

移除工作区(我们将直接使用项目或创建新工作区)

rm -rf App.xcworkspace
undefined
rm -rf App.xcworkspace
undefined

Step 4: Add SPM Dependencies in Xcode

步骤4:在Xcode中添加SPM依赖项

  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
  1. 在Xcode中打开
    ios/App/App.xcodeproj
  2. 在导航栏中选择项目
  3. 进入Package Dependencies标签页
  4. 点击**+**添加包
  5. 输入包的URL
  6. 选择版本规则
  7. 选择目标
    App

Step 5: Update Podfile for Capacitor Core

步骤5:为Capacitor Core更新Podfile

Capacitor still needs CocoaPods for its core. Create minimal Podfile:
ruby
undefined
Capacitor核心仍需依赖CocoaPods。创建极简Podfile:
ruby
undefined

ios/App/Podfile

ios/App/Podfile

require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
platform :ios, '14.0' use_frameworks!
install! 'cocoapods', :disable_input_output_paths => true
def capacitor_pods pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' end
target 'App' do capacitor_pods

Other plugin pods that don't support SPM yet

end
post_install do |installer| assertDeploymentTarget(installer) end

Then run:
```bash
cd ios/App && pod install
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
platform :ios, '14.0' use_frameworks!
install! 'cocoapods', :disable_input_output_paths => true
def capacitor_pods pod 'Capacitor', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' end
target 'App' do capacitor_pods

其他暂不支持SPM的插件Pods

end
post_install do |installer| assertDeploymentTarget(installer) end

然后运行:
```bash
cd ios/App && pod install

Step 6: Configure Plugin for SPM Support

步骤6:配置插件以支持SPM

If you're creating a Capacitor plugin with SPM support:
Package.swift:
swift
// swift-tools-version: 5.9
import PackageDescription

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"
        ),
    ]
)
如果你正在创建支持SPM的Capacitor插件:
Package.swift:
swift
// swift-tools-version: 5.9
import PackageDescription

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"
        ),
    ]
)

Step 7: Xcode Project Structure for SPM

步骤7:SPM的Xcode项目结构

ios/
├── App/
│   ├── App/
│   │   ├── AppDelegate.swift
│   │   ├── Info.plist
│   │   └── ...
│   ├── App.xcodeproj/
│   │   └── project.xcworkspace/
│   │       └── xcshareddata/
│   │           └── swiftpm/
│   │               └── Package.resolved  # SPM lock file
│   ├── Podfile
│   └── Podfile.lock
└── ...
ios/
├── App/
│   ├── App/
│   │   ├── AppDelegate.swift
│   │   ├── Info.plist
│   │   └── ...
│   ├── App.xcodeproj/
│   │   └── project.xcworkspace/
│   │       └── xcshareddata/
│   │           └── swiftpm/
│   │               └── Package.resolved  # SPM锁定文件
│   ├── Podfile
│   └── Podfile.lock
└── ...

Hybrid Approach (Recommended)

混合方案(推荐)

Most Capacitor projects work best with a hybrid approach:
大多数Capacitor项目使用混合方案效果最佳:

Keep in CocoaPods:

保留在CocoaPods中的内容:

  • @capacitor/ios
    core
  • Capacitor plugins without SPM support
  • @capacitor/ios
    核心库
  • 暂不支持SPM的Capacitor插件

Move to SPM:

迁移至SPM的内容:

  • Firebase
  • Third-party libraries
  • Your own Swift packages
  • Firebase
  • 第三方库
  • 自定义Swift包

Example Hybrid Setup

混合方案示例

Podfile:
ruby
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'

platform :ios, '14.0'
use_frameworks!

install! 'cocoapods', :disable_input_output_paths => true

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

target 'App' do
  capacitor_pods
  # NO Firebase here - use SPM instead
end
Xcode Package Dependencies:
  • Firebase iOS SDK
  • Any other SPM-compatible libraries
Podfile:
ruby
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'

platform :ios, '14.0'
use_frameworks!

install! 'cocoapods', :disable_input_output_paths => true

def capacitor_pods
  pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
  pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
  # 暂不支持SPM的插件
  pod 'CapacitorCamera', :path => '../../node_modules/@capacitor/camera'
end

target 'App' do
  capacitor_pods
  # 此处不添加Firebase - 改用SPM
end
Xcode包依赖项:
  • Firebase iOS SDK
  • 其他支持SPM的库

Common Issues and Solutions

常见问题及解决方案

Issue: Duplicate Symbols

问题:重复符号

Cause: Same library in both CocoaPods and SPM
Solution: Remove from Podfile if using SPM
ruby
undefined
原因:同一库同时存在于CocoaPods和SPM中
解决方案:如果使用SPM,从Podfile中移除该库
ruby
undefined

Podfile - WRONG

Podfile - 错误写法

pod 'Firebase/Analytics' # Remove this
pod 'Firebase/Analytics' # 移除这一行

Use SPM instead in Xcode

改用Xcode中的SPM添加

undefined
undefined

Issue: Module Not Found

问题:模块未找到

Cause: SPM package not linked to target
Solution:
  1. Xcode > Project > Targets > App
  2. General > Frameworks, Libraries, and Embedded Content
  3. Add the SPM package product
原因:SPM包未关联至目标
解决方案:
  1. Xcode > 项目 > 目标 > App
  2. 常规 > 框架、库和嵌入式内容
  3. 添加SPM包产物

Issue: Build Errors After Migration

问题:迁移后出现构建错误

Cause: Missing frameworks or wrong imports
Solution: Clean and rebuild
bash
undefined
原因:缺少框架或导入错误
解决方案:清理并重新构建
bash
undefined

Clean derived data

清理派生数据

rm -rf ~/Library/Developer/Xcode/DerivedData
rm -rf ~/Library/Developer/Xcode/DerivedData

Clean build folder in Xcode

在Xcode中清理构建文件夹

Cmd + Shift + K

Cmd + Shift + K

Rebuild

重新构建

bunx cap sync ios cd ios/App && pod install
undefined
bunx cap sync ios cd ios/App && pod install
undefined

Issue: Capacitor Plugin Not Found

问题:Capacitor插件未找到

Cause: Plugin needs registration
Solution: Ensure plugin is registered in
AppDelegate.swift
:
swift
import Capacitor
import YourPlugin

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Capacitor handles plugin registration automatically
        return true
    }
}
原因:插件未注册
解决方案:确保插件已在
AppDelegate.swift
中注册:
swift
import Capacitor
import YourPlugin

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        // Capacitor会自动处理插件注册
        return true
    }
}

Creating SPM-Compatible Capacitor Plugin

创建支持SPM的Capacitor插件

Directory Structure

目录结构

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
my-capacitor-plugin/
├── Package.swift
├── ios/
│   └── Sources/
│       └── MyPlugin/
│           ├── MyPlugin.swift
│           ├── MyPlugin.m           # 如需Objective-C桥接文件
│           └── include/
│               └── MyPlugin.h       # 公开头文件
├── src/
│   ├── index.ts
│   ├── definitions.ts
│   └── web.ts
└── package.json

Package.swift Template

Package.swift模板

swift
// swift-tools-version: 5.9
import PackageDescription

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"
        ),
    ]
)
swift
// swift-tools-version: 5.9
import PackageDescription

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"
        ),
    ]
)

Plugin Swift Code

插件Swift代码

swift
import Foundation
import Capacitor

@objc(MyPlugin)
public class MyPlugin: CAPPlugin, CAPBridgedPlugin {
    public let identifier = "MyPlugin"
    public let jsName = "MyPlugin"
    public let pluginMethods: [CAPPluginMethod] = [
        CAPPluginMethod(name: "echo", returnType: CAPPluginReturnPromise),
    ]

    @objc func echo(_ call: CAPPluginCall) {
        let value = call.getString("value") ?? ""
        call.resolve(["value": value])
    }
}
swift
import Foundation
import Capacitor

@objc(MyPlugin)
public class MyPlugin: CAPPlugin, CAPBridgedPlugin {
    public let identifier = "MyPlugin"
    public let jsName = "MyPlugin"
    public let pluginMethods: [CAPPluginMethod] = [
        CAPPluginMethod(name: "echo", returnType: CAPPluginReturnPromise),
    ]

    @objc func echo(_ call: CAPPluginCall) {
        let value = call.getString("value") ?? ""
        call.resolve(["value": value])
    }
}

Migration Checklist

迁移检查清单

  • 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
  • 列出所有当前CocoaPods依赖项
  • 为每个依赖项找到SPM替代方案
  • 运行
    pod deintegrate
  • 在Xcode中添加SPM包
  • 为Capacitor核心创建极简Podfile
  • 运行
    pod install
  • 清理派生数据
  • 构建并测试
  • Package.resolved
    提交至git
  • 如有需要,更新CI/CD脚本

Resources

资源