CocoaPods 只读后怎么办?iOS 工程从 CocoaPods 迁移到 SPM
CocoaPods trunk 将在 2026 年 12 月 2 日变为只读,已发布的版本仍能 pod install,但依赖不再更新。本文讲清影响和是否该迁移,给出常用库的 SPM 支持对照和迁移到 Swift Package Manager 的 7 个步骤。
CocoaPods 只读从 2026 年 12 月 2 日开始,trunk 之后不再接受新的 pod 和新版本。已经发布的版本照常能 pod install,现有工程不会因此编译失败,但依赖从此拿不到更新。还在持续开发的工程,应该逐个库迁移到 Swift Package Manager(SPM):盘点 Podfile.lock,移除一个 pod,加上对应的 Swift Package,编译并真机验证后再迁下一个。下文给出常用库的 SPM 支持对照和 7 个迁移步骤。
时间和影响以 CocoaPods Trunk Read-only Plan 原文为准,下文内容截至 2026 年 10 月。
CocoaPods 只读后影响什么?
CocoaPods 博客在 2024 年 11 月 30 日公布了计划,时间表如下。
| 时间 | 事件 |
|---|---|
| 2025 年 5 月 | 新 pod 不能再使用 prepare_command 字段,已有的不受影响 |
| 2026 年 9–10 月 | 再次邮件通知所有发布过 Podspec 的作者 |
| 2026 年 11 月 1–7 日 | 进行一次只读试运行 |
| 2026 年 12 月 2 日 | trunk 永久停止接受新的 Podspec |
对使用 CocoaPods 的工程,影响分这几种。
| 情况 | 只读之后 |
|---|---|
pod install 已经发布过的版本 |
照常能装,博客说明 Specs 仓库和 CDN 会继续运行 |
| 想升级到库的新版本 | 库作者没法再往 trunk 发新版本,pod update 拿不到 |
自建 spec 仓库、:path、:git 引用的库 |
不经过 trunk,不受影响 |
| 依赖已经全部 vendored 进仓库 | 不受影响 |
不少库已经提前行动。Firebase 的迁移说明写明,2026 年 10 月起不再向 CocoaPods 发布新版本,CocoaPods 上的最后一个大版本是 Firebase 12,已有版本仍可安装。之后的更新要通过 SPM 或 Firebase 提供的 zip 包获取,官方首推 SPM。
哪些工程该迁移到 SPM?
| 你的情况 | 建议 |
|---|---|
| 还在持续开发,依赖要跟着升级 | 尽早迁移到 SPM,先从更新频繁的库开始 |
| 用了 Firebase 等已宣布停发 CocoaPods 的 SDK | 优先迁移这些库 |
| 工程基本不再改,只偶尔出包 | 可以不急,锁定 Podfile.lock 照常构建 |
| 依赖里有不支持 SPM 的老库 | 先迁移其他库,这个库保留 pod,或者换成替代库 |
| 全是内部私有 pod、自建 spec 仓库 | 不受只读影响,按团队计划决定 |
迁移不必一次完成。CocoaPods 和 SPM 可以在同一个工程里共存,逐个库迁移、每迁一个就编译验证一次,风险最小。
常用库支持 SPM 吗?
下表是各库仓库根目录是否提供 Package.swift,以及 SPM 里的产品名。添加时用这个地址和产品名,以各库 README 为准。
| 库 | SPM 地址 | 产品名 | 说明 |
|---|---|---|---|
| Alamofire | https://github.com/Alamofire/Alamofire.git |
Alamofire | 支持 |
| SDWebImage | https://github.com/SDWebImage/SDWebImage.git |
SDWebImage | 支持 |
| Kingfisher | https://github.com/onevcat/Kingfisher.git |
Kingfisher | 支持 |
| SnapKit | https://github.com/SnapKit/SnapKit.git |
SnapKit | 支持 |
| Firebase | https://github.com/firebase/firebase-ios-sdk.git |
FirebaseAnalytics、FirebaseMessaging、FirebaseCrashlytics、FirebaseAuth 等 | 支持,按用到的模块分别选产品 |
| Lottie | https://github.com/airbnb/lottie-spm.git |
Lottie | 支持,官方建议用 lottie-spm 这个小仓库 |
| Realm | https://github.com/realm/realm-swift.git |
RealmSwift(Objective-C 用 Realm) | 支持 |
| RxSwift | https://github.com/ReactiveX/RxSwift.git |
RxSwift、RxCocoa、RxRelay | 支持 |
| Moya | https://github.com/Moya/Moya.git |
Moya、RxMoya、CombineMoya | 支持,依赖 Alamofire,两者一起迁 |
| SwiftyJSON | https://github.com/SwiftyJSON/SwiftyJSON.git |
SwiftyJSON | 支持 |
| IQKeyboardManager | https://github.com/hackiftekhar/IQKeyboardManager.git |
IQKeyboardManagerSwift | 支持 |
| MJRefresh | https://github.com/CoderMJLee/MJRefresh.git |
MJRefresh | 支持 |
| MBProgressHUD | https://github.com/jdg/MBProgressHUD.git |
MBProgressHUD | 支持 |
| SVProgressHUD | https://github.com/SVProgressHUD/SVProgressHUD.git |
SVProgressHUD | 支持 |
| MMKV | https://github.com/Tencent/MMKV.git |
MMKV | 支持 |
| KeychainAccess | https://github.com/kishikawakatsumi/KeychainAccess.git |
KeychainAccess | 支持 |
| Google Sign-In | https://github.com/google/GoogleSignIn-iOS.git |
GoogleSignIn、GoogleSignInSwift | 支持 |
| Facebook SDK | https://github.com/facebook/facebook-ios-sdk.git |
FacebookCore、FacebookLogin、FacebookShare 等 | 支持 |
| Masonry | — | — | 仓库没有 Package.swift。Swift 工程可改用 SnapKit,或继续用 pod |
| AFNetworking | — | — | 2023 年 1 月起已停止维护,建议换成 Alamofire 或 URLSession |
| YYModel | — | — | 仓库没有 Package.swift,可改用 Codable,或继续用 pod |
表里没有的库,打开它的 GitHub 仓库看根目录有没有 Package.swift,README 里一般也会写 SPM 的安装方法。一些国内常见的闭源 SDK 只提供 pod 或手动集成,以 SDK 官方文档为准。
怎么从 CocoaPods 迁移到 SPM?
下面以一个用 .xcworkspace 构建的 MyApp 为例,把 Alamofire 从 pod 换成 Swift Package。开始前新建一个分支,确认工程当前能编译通过。
1. 盘点依赖
打开 Podfile.lock,列出每个 pod 和当前锁定的版本,对照上一节标出哪些支持 SPM。注意 pod 之间的依赖关系,比如 Moya 依赖 Alamofire,这类要一起迁,否则同一个库会出现两份。
Podfile 里的版本写法换成 SPM 的版本规则,对应关系如下。
| Podfile | 含义 | SPM 版本规则 |
|---|---|---|
pod 'Alamofire', '~> 5.9' |
5.9 及以上、6.0 以下 | 从 5.9.0 到下一个主版本 |
pod 'Alamofire', '~> 5.9.1' |
5.9.1 及以上、5.10 以下 | 从 5.9.1 到下一个次版本 |
pod 'Alamofire', '5.9.1' |
固定这一个版本 | 固定 5.9.1 |
迁移时先用 Podfile.lock 里锁定的版本,迁移完成、编译通过后再单独升级,出问题时容易分辨原因。
2. 移除一个 pod
在 Podfile 里删掉或注释掉这一行,然后在 Podfile 所在目录重新安装。
1target 'MyApp' do
2 use_frameworks!
3 # pod 'Alamofire', '~> 5.9'
4 pod 'SDWebImage'
5end
1pod install
3. 添加 Swift Package
在 Windows、Linux、macOS 上用 KXBuild 时,以下两种做法任选其一。
- VS Code 插件。命令面板运行
KXBuild: 添加 Swift Package 依赖…,或在 KXBuild 视图中右键 MyApp target 选择它。输入包的 Git 地址,选版本规则和产品 Alamofire。 - 命令行。在工程目录执行下面的命令,
-P填.xcodeproj,不是.xcworkspace。
1kxbuild project add-package -P .\MyApp.xcodeproj -t MyApp --url https://github.com/Alamofire/Alamofire.git --from 5.9.0 --product Alamofire
固定版本用 --exact 5.9.1,到下一个次版本用 --up-to-next-minor 5.9.1,其他参数见 project add-package。添加时需要联网,产品名不对或解析失败时工程保持原样。
4. 改 import 和代码
大多数库的模块名和 pod 一样,import Alamofire、import Kingfisher 不用改。需要检查的是这几类。
- 按模块拆分的 SDK。Firebase 这类在 SPM 里分成多个产品,按用到的产品 import,例如
import FirebaseCore、import FirebaseAnalytics。 - 产品名不同的库。IQKeyboardManager 的产品是 IQKeyboardManagerSwift,Realm 的 Swift 接口是 RealmSwift,import 写产品对应的模块名。
- Objective-C 头文件。
#import <SDWebImage/SDWebImage.h>一般仍可用,也可以改成@import SDWebImage;。
改完先编译一次。Pods 目录还在时继续构建 .xcworkspace。
1kxbuild build .\MyApp.xcworkspace -D CODE_SIGNING_ALLOWED=NO
5. 处理资源 bundle
用 pod 时,有些代码按名字去 App 里找库的资源包,例如 Bundle.main.path(forResource: "XXX", ofType: "bundle")。换成 SPM 后资源包的名字和位置会变,这类代码会返回 nil,界面上图标、本地化文字消失,或者运行时崩溃。
- 全局搜索
forResource:和.bundle,找出读取第三方库资源的地方。 - 优先改用库提供的公开接口,不要自己拼资源包路径。
- 你自己的本地包读取包内资源时用
Bundle.module,这个属性只在包的代码里能用。
6. 编译、真机验证、提交
编译通过后按 F5 装到手机,把用到这个库的功能都点一遍。启动后报 unrecognized selector 的,多半是 Objective-C 库的分类没被链接进来。CocoaPods 默认会给工程加 -ObjC,迁移后在 target 的 Other Linker Flags 里补上,用工程设置编辑器或下面的命令都行。
1kxbuild project add-setting -k OTHER_LDFLAGS -v '$(inherited),-ObjC' -a -t MyApp -P .\MyApp.xcodeproj
一切正常就提交这次改动,包括 Podfile、Podfile.lock、project.pbxproj 和 SPM 生成的 Package.resolved。然后回到第 2 步迁下一个库。
7. 最后一个 pod 迁完后
所有 pod 都换成 Swift Package 之后,再彻底移除 CocoaPods。不要提前删 Pods 和工作区,那时还有库在用它们。
- 在 Podfile 所在目录运行
pod deintegrate,它会从工程里移除 CocoaPods 加的构建阶段和配置。 - 删除 Podfile、Podfile.lock 和 Pods 目录。
- 工作区里只有 MyApp.xcodeproj 和 Pods 时,删掉 MyApp.xcworkspace。工作区里还有别的工程的保留。
- 在 KXBuild 视图把启动项目切到 MyApp.xcodeproj,构建、CI 脚本里的
.xcworkspace也都改成.xcodeproj。
1kxbuild build .\MyApp.xcodeproj -c Release
CI 里建议加上 --only-use-versions-from-resolved-file,严格按 Package.resolved 的版本构建,参数说明见构建与配置。
CocoaPods 和 SPM 能混用吗?
- 同一个库只留一个来源。一个库既在 Podfile 里又加成了 Swift Package,会出现重复符号或运行时两份实例。间接依赖也算,比如 pod 里的 Moya 会带进 Alamofire。
- 混用期间构建
.xcworkspace。Swift Package 加在.xcodeproj上,从工作区构建时会一起解析。 - 每次改 Podfile 后都要
pod install,再构建。 - 一次只迁一个库。出问题时回退一个提交就行,不用排查一堆改动。
Flutter 和 React Native 工程怎么办?
Flutter。按 Flutter 官方的 Swift Package Manager 说明,从 3.44 起 SPM 支持默认开启,升级 Flutter 后运行 App 会自动加上 SPM 集成。工程里有插件还不支持 SPM 时,Flutter 会对这些插件退回 CocoaPods,这时照常在 ios 目录运行 pod install,做法见 Flutter iOS 构建。Flutter 文档还提醒,以后将不再允许关闭 SPM,所以不要关掉它,而是把插件逐步升级到支持 SPM 的版本。
React Native 和 Expo。iOS 端目前仍通过 ios 目录的 Podfile 安装原生依赖。CocoaPods 只读后的迁移方式请关注 React Native 和 Expo 官方的进展,在官方给出方案前不要自己把 Pods 换成 Swift Package。日常构建做法见 React Native 技术栈。
常见问题
CocoaPods 只读后 pod install 还能用吗?
能用。已经发布到 trunk 的版本照常可以安装,现有工程按 Podfile.lock 构建不受影响。变化是库作者不能再往 trunk 发布新版本,你拿不到后续更新。
CocoaPods trunk 什么时候变成只读?
按 CocoaPods 官方博客的计划,2026 年 12 月 2 日永久停止接受新的 Podspec,之前的 11 月 1 日到 7 日会做一次只读试运行。
一定要把所有 pod 都换成 Swift Package 吗?
不一定。还在持续开发、需要升级依赖的库应该迁移,不再更新的老工程可以锁定 Podfile.lock 继续用。不支持 SPM 的库可以先保留 pod,两者能在同一个工程里共存。
迁移后编译报 no such module 怎么办?
先确认包已经加到正在构建的那个 target,产品名选对了,import 写的是产品对应的模块名,比如 IQKeyboardManagerSwift、FirebaseAnalytics。还在用 Pods 时要构建 .xcworkspace。仍然报错的,运行 kxbuild project resolve .\MyApp.xcworkspace --force 重新解析依赖。
Flutter 工程要自己迁移到 SPM 吗?
不用手动改。Flutter 3.44 起默认开启 SPM,升级 Flutter 后运行 App 会自动接入,插件不支持 SPM 时自动退回 CocoaPods。你要做的是把插件升级到支持 SPM 的版本。