关于 capacitor-app-spm-migration
该技能指导将现有 Capacitor 应用的 iOS 依赖管理从 CocoaPods 迁移到 Swift Package Manager。它面向维护 Capacitor 6+ 应用的开发者,重点是重建 iOS 工程前备份并恢复用户文件、配置和插件。
主要功能
- 01迁移前检查项目与工作区状态
- 02盘点插件并备份自定义文件
- 03使用 SPM 重新生成 iOS 工程
- 04恢复签名配置并重新同步插件
- 05检查能力配置并验证构建
适用场景
- 01将现有 Capacitor 应用切换到 SPM
- 02迁移时保留 iOS 自定义代码与资源
- 03检查插件的 SPM 兼容情况
- 04迁移后验证签名和应用构建
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ capawesome-team/ skills --skill capacitor-app-spm-migration安装后在 Claude Code 中输入/capacitor-app-spm-migration确认已加载。
详细介绍
Capacitor 应用:从 CocoaPods 迁移到 SPM
将现有 Capacitor 应用项目的 iOS 依赖管理从 CocoaPods 迁移到 Swift Package Manager(SPM)。此迁移具有破坏性——现有的 ios/ 文件夹会被删除并重新生成,然后从临时备份中恢复用户编写的文件。
前置条件
| 要求 | 版本 |
|---|---|
| Capacitor | 6+ |
| Node.js | 18+ |
| Xcode | 15+ |
| CocoaPods | 已安装(仅在删除前用于验证) |
项目必须是 Capacitor 应用(而非插件),并且当前必须使用 CocoaPods(存在 ios/App/Podfile)。
流程
步骤 1:验证项目状态
- 验证项目是 Capacitor 应用,而非插件。确认
package.json在dependencies中列出了@capacitor/ios,且项目根目录包含一个capacitor.config.*文件。 - 验证项目当前使用 CocoaPods。文件
ios/App/Podfile必须存在。如果该文件不存在,而ios/App/CapApp-SPM/Package.swift存在,则项目已使用 SPM——中止并告知用户。 - 从
package.json(dependencies或devDependencies)读取@capacitor/core版本。确认主版本为 6 或更高。如果低于此版本,则中止并先引导用户使用capacitor-app-upgrades技能。 - 验证工作树干净。运行
git status --porcelain——如果输出非空,指示用户在继续之前提交或暂存更改。此迁移具有破坏性,必须能够通过git checkout还原。
步骤 2:盘点已安装的 Capacitor 插件
读取 package.json,记录 dependencies 下安装的所有 Capacitor 插件。匹配以下前缀:
@capacitor/*(官方插件)@capawesome/*和@capawesome-team/*@capacitor-community/*@capacitor-firebase/*@capacitor-mlkit/*@revenuecat/*- 其他任何在其
package.json的keywords数组中包含"capacitor"的包
记录每个插件的包名和已安装版本。此列表将在步骤 8 中用于验证重新同步后所有插件是否都能通过 SPM 解析。
步骤 3:确定需要保留的文件
创建一份清单,列出 ios/ 中包含用户编写内容且必须在重新生成后保留的文件。检查以下每个路径是否存在,并且只记录存在的路径。
| 路径(相对于项目根目录) | 用途 |
|---|---|
ios/App/App/Info.plist | 应用权限、URL 方案、包配置、自定义键 |
ios/App/App/AppDelegate.swift | 自定义应用生命周期代码 |
ios/App/App/SceneDelegate.swift | 自定义场景生命周期代码(如果存在) |
ios/App/App/Assets.xcassets/ | 应用图标、启动屏幕资源、颜色集 |
ios/App/App/Base.lproj/ | LaunchScreen 和 Main 故事板 |
ios/App/App/App.entitlements | 推送、App Groups、关联域、Keychain Sharing |
ios/App/App/GoogleService-Info.plist | Firebase 配置(如果安装了 Firebase 插件) |
ios/App/App/*.xcconfig | 构建配置覆盖项 |
ios/App/App.xcodeproj/project.pbxproj | 用于提取步骤 5 中签名值的源文件 |
此外,扫描 ios/App/App/,查找除 AppDelegate.swift 和 SceneDelegate.swift 以外的任何其他 .swift 文件。这些是用户编写的 Swift 源文件(例如,自定义 Notification Service Extension、自定义视图控制器),也必须保留。
如果项目包含 Notification Service Extension 或 ios/App/ 下的其他 Xcode 目标(例如 ios/App/NotificationService/),也记录这些目录。
步骤 4:备份保留的文件
-
创建备份目录:
mkdir -p .spm-migration-backup -
将
.spm-migration-backup/添加到.gitignore,以防意外提交:# iOS files +.spm-migration-backup/ -
将步骤 3 中记录的每个文件复制到
.spm-migration-backup/,并保留相对路径。例如:mkdir -p .spm-migration-backup/ios/App/App cp ios/App/App/Info.plist .spm-migration-backup/ios/App/App/Info.plist cp ios/App/App/AppDelegate.swift .spm-migration-backup/ios/App/App/AppDelegate.swift cp -R ios/App/App/Assets.xcassets .spm-migration-backup/ios/App/App/Assets.xcassets cp -R ios/App/App/Base.lproj .spm-migration-backup/ios/App/App/Base.lproj对步骤 3 中识别出的每个文件/目录重复此操作。目录请使用
cp -R。 -
始终将完整的
ios/App/App.xcodeproj/project.pbxproj复制到.spm-migration-backup/ios/App/App.xcodeproj/project.pbxproj,尽管不会还原该文件本身。步骤 5 会读取它以提取签名值,步骤 11 可能会参考它重新配置功能。
步骤 5:提取签名和 Bundle 配置
读取 .spm-migration-backup/ios/App/App.xcodeproj/project.pbxproj,并从 App 目标的 XCBuildConfiguration 块(包括 Debug 和 Release)中提取以下构建设置的值。搜索每个键并记录其赋值:
PRODUCT_BUNDLE_IDENTIFIERDEVELOPMENT_TEAMCODE_SIGN_STYLE(例如Automatic或Manual)PROVISIONING_PROFILE_SPECIFIER(仅当CODE_SIGN_STYLE = Manual时)CODE_SIGN_IDENTITY(仅当CODE_SIGN_STYLE = Manual时)MARKETING_VERSIONCURRENT_PROJECT_VERSIONIPHONEOS_DEPLOYMENT_TARGETSWIFT_VERSION
还要读取 .spm-migration-backup/ios/App/App/App.entitlements(如果存在),并记录功能列表。记录所有顶层键(例如 aps-environment、com.apple.security.application-groups、com.apple.developer.associated-domains)。
将提取的值保存在内存中,以便在步骤 9 中使用。
步骤 6:删除 ios/ 文件夹
向用户确认工作树已提交(必要时重新运行 git status --porcelain),并确认 .spm-migration-backup/ 包含步骤 3 中的所有文件。然后运行:
rm -rf ios
步骤 7:使用 SPM 重新生成 iOS 脚手架
运行:
npx cap add ios --packagemanager SPM
这会创建一个新的 ios/ 目录,其中包含基于 SPM 的脚手架。新结构包含 ios/App/CapApp-SPM/Package.swift,而非 ios/App/Podfile。
步骤 8:还原保留的文件
将备份的每个文件从 .spm-migration-backup/ 复制回 ios/ 下的原始路径,覆盖脚手架默认文件。例如:
cp .spm-migration-backup/ios/App/App/Info.plist ios/App/App/Info.plist
cp .spm-migration-backup/ios/App/App/AppDelegate.swift ios/App/App/AppDelegate.swift
cp -R .spm-migration-backup/ios/App/App/Assets.xcassets ios/App/App/Assets.xcassets
cp -R .spm-migration-backup/ios/App/App/Base.lproj ios/App/App/Base.lproj
对步骤 4 中备份的每个文件/目录重复此操作,但不包括 ios/App/App.xcodeproj/project.pbxproj——该文件不会还原。SPM 集成需要新的 project.pbxproj;旧文件中的签名值将在步骤 9 中重新应用。
如果新脚手架中不存在某个保留文件(例如 App.entitlements、GoogleService-Info.plist、自定义 Swift 文件),还必须在步骤 10 中将该文件添加到 Xcode 项目成员中。
步骤 9:重新应用签名和 Bundle 配置
编辑新的 ios/App/App.xcodeproj/project.pbxproj,并重新应用步骤 5 中提取的值。对于每项设置,在 App 目标的 XCBuildConfiguration 块中查找每个出现位置,并将脚手架生成的值替换为记录的值。
对每项设置应用此差异模式(以 PRODUCT_BUNDLE_IDENTIFIER 为例):
- PRODUCT_BUNDLE_IDENTIFIER = com.example.app;
+ PRODUCT_BUNDLE_IDENTIFIER = <RECORDED_BUNDLE_ID>;
需要重新应用的设置(使用 replace_all 语义——更新 Debug 和 Release 配置中的所有出现位置):
PRODUCT_BUNDLE_IDENTIFIERDEVELOPMENT_TEAMCODE_SIGN_STYLEPROVISIONING_PROFILE_SPECIFIER(仅适用于手动签名)CODE_SIGN_IDENTITY(仅适用于手动签名)MARKETING_VERSIONCURRENT_PROJECT_VERSION
如果记录的 IPHONEOS_DEPLOYMENT_TARGET 高于脚手架生成的值,则更新它。如果低于,则保留脚手架生成的值(新脚手架针对受支持的最低版本)。
步骤 10:将恢复的自定义文件添加到 Xcode 项目
新的 project.pbxproj 仅引用脚手架创建的文件。第 8 步恢复的文件中,凡是脚手架中不存在的文件(例如 App.entitlements、GoogleService-Info.plist、自定义 Swift 文件、Notification Service Extension 目标),虽然已存在于磁盘上,但在添加到项目的 PBXBuildFile、PBXFileReference 和 PBXGroup 条目之前,Xcode 中都不可见。
对于每个不属于脚手架的自定义文件,告知用户在 Xcode 中执行以下一次性操作(SPM 脚手架没有 App.xcworkspace,请直接打开 App.xcodeproj):
- 打开项目:
npx cap open ios(或open ios/App/App.xcodeproj)。 - 在 Xcode 项目导航器中,右键点击
App组,然后选择 Add Files to "App"…。 - 选择每个恢复的自定义文件(例如
App.entitlements、GoogleService-Info.plist、自定义.swift文件)。 - 确保 Copy items if needed 未勾选,并且
App目标已勾选。
对于 App.entitlements 文件,还需在 ios/App/App.xcodeproj/project.pbxproj 中设置 CODE_SIGN_ENTITLEMENTS 构建设置。将此差异模式同时应用于 App 目标的 Debug 和 Release XCBuildConfiguration 块:
CODE_SIGN_STYLE = Automatic;
+ CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
CURRENT_PROJECT_VERSION = 1;
如果项目还有其他 Xcode 目标(例如 ios/App/NotificationService/ 下的 Notification Service Extension),用户必须在 Xcode 中重新创建这些目标。SPM 脚手架不会重新生成非 App 目标。请明确告知用户。
步骤 11:重新配置功能
对于第 5 步中从 App.entitlements 记录的每个功能键,请确认 Xcode 中已启用对应功能:
- 通过
npx cap open ios打开ios/App/App.xcodeproj。 - 选择
App目标 → Signing & Capabilities 标签页。 - 对于每个 entitlement 键,通过 + Capability 按钮添加匹配的功能:
aps-environment→ Push Notificationscom.apple.security.application-groups→ App Groupscom.apple.developer.associated-domains→ Associated Domainskeychain-access-groups→ Keychain Sharingcom.apple.developer.in-app-payments→ Apple Paycom.apple.developer.icloud-services→ iCloud
这是唯一需要与 Xcode 交互的步骤。请明确告知用户必须手动完成此步骤。
步骤 12:重新同步插件
运行:
npm install
npx cap sync ios
npx cap sync ios 会更新 ios/App/CapApp-SPM/Package.swift,以包含第 2 步中记录的所有 Capacitor 插件。留意警告——此处会报告任何不支持 SPM 的插件。
如果报告某个插件与 SPM 不兼容,请告知用户。用户必须选择以下操作之一:
- 等待插件维护者提供上游 SPM 支持,或
- Fork 该插件,并使用
capacitor-plugin-spm-supportskill 添加 SPM 支持,或 - 从项目中移除该插件。
步骤 13:验证构建
-
在 Xcode 中打开项目并解析 SPM 包:
npx cap open ios在 Xcode 中选择 File → Packages → Resolve Package Versions(或等待打开时自动解析)。
-
从命令行构建模拟器版本,确认所有内容均可编译:
npx cap run ios -
确认应用可以启动,且之前正常运行的功能(推送通知、深层链接、Firebase 等)仍然可用。
步骤 14:清理
构建验证通过且应用正常运行后:
-
删除备份目录:
rm -rf .spm-migration-backup -
从
.gitignore中移除.spm-migration-backup/条目。 -
确认没有残留 CocoaPods 产物:
find ios -name 'Podfile*' -o -name 'Pods' -o -name '*.xcworkspace'如果有任何结果,请将其删除。SPM 工作流直接使用
App.xcodeproj——不存在App.xcworkspace。 -
提交迁移:
git add -A git commit -m "chore(ios): migrate from CocoaPods to Swift Package Manager"
错误处理
npx cap add ios --packagemanager SPM失败并提示 "ios platform already exists" — 第 6 步未完成。重新运行rm -rf ios,然后重试。npx cap sync ios报告某个插件不支持 SPM — 在该插件提供Package.swift之前,无法在 SPM 下使用它。告知用户并暂停迁移;不要悄悄移除该插件。- 构建失败并提示 "Module 'X' not found" — 插件的 SPM 包尚未解析。在 Xcode 中运行 File → Packages → Reset Package Caches,然后运行 File → Packages → Resolve Package Versions。
- 构建因代码签名错误而失败 — 第 9 步重新应用的值缺失或不正确。重新读取
.spm-migration-backup/ios/App/App.xcodeproj/project.pbxproj,并确认已将DEVELOPMENT_TEAM和PRODUCT_BUNDLE_IDENTIFIER应用于Debug和Release两种配置。 - 迁移后推送通知停止工作 — 第 11 步未重新添加 Push Notifications 功能,或者
App.entitlements未通过CODE_SIGN_ENTITLEMENTS关联(第 10 步)。 - Firebase 已初始化,但没有数据显示 —
GoogleService-Info.plist已恢复到磁盘,但在第 10 步中未添加到 Xcode 项目的目标成员资格中。 - 缺少自定义 Notification Service Extension 目标 —
npx cap add ios不会重新生成非App目标。请在 Xcode 中手动重新创建该目标,并重新添加其源文件。 - 用户表示想要回退 — 由于第 1 步已确认工作树干净,可以使用
git checkout -- .,然后运行git clean -fd ios .spm-migration-backup撤销整个迁移。
相关技能
capacitor-plugin-spm-support— 用于为 Capacitor 插件(而非应用)添加 SPM 支持。如果第 12 步报告某个插件不支持 SPM,且用户拥有该插件的源代码,请使用此技能。capacitor-plugins— 用于在迁移后安装或重新配置 Capacitor 插件。capacitor-app-upgrades— 如果项目使用 Capacitor 5 或更早版本,请先使用此技能将其升级到 Capacitor 6+,然后再返回此处。capacitor-app-development— 用于迁移后的 Capacitor 应用开发常见主题、故障排除和最佳实践。