iOS 私有库创建与推送远程——问题排查总结文档
场景:使用 CocoaPods 创建 iOS 私有库并推送到 Gitee 远程仓库,过程中遇到的一系列报错与解决记录。 适用对象:iOS 开发者 / CocoaPods 私有组件维护者。
一、核心概念(必须分清两个仓库)
| 仓库 | 作用 | 内容 | 使用命令 |
|---|---|---|---|
源码仓库 my-private-sdk | 存放组件代码 | Classes/ 源码、.podspec、git tag | git remote add / git push / git tag |
Spec 索引仓库 my-private-specs | 存放 podspec 描述索引 | 各版本 0.1.0/xxx.podspec(不放源码) | pod repo add / pod repo push |
⚠️ 两个仓库必须分开、独立,绝对不能混用地址,这是整套方案最容易出错的地方。
关键理解:一个 Spec 仓库可管理多个私有组件
- 源码仓库:每新增一个私有库,就要新建一个独立的源码仓库(组件代码互相独立)
- Spec 索引仓库:全局只维护 1 个,所有内部组件的 podspec 都集中放这里,一次创建、长期复用
- 所以新增第二个、第三个私有库时,不需要新建 Spec 仓库,复用已有的
MyPrivateSpecs即可
二、完整正确步骤(标准私有库方案·创建第一个库)
0. 前置
- 本地安装 CocoaPods:
gem install cocoapods,验证pod --version - Gitee 网页新建两个空仓库:
my-private-sdk(源码仓库)my-private-specs(Spec 索引仓库)
- ⚠️ 创建时不要勾选 README、.gitignore、license,必须是纯空仓库
1. 创建本地私有库模板
pod lib create MyPrivateSDK
# 交互选择:iOS / ObjC或Swift / 带Demo / 测试框架None
cd MyPrivateSDK
- 代码放入
MyPrivateSDK/Classes/(不是 Example)
2. 修改 podspec
- 重点:
s.version、s.source(指向源码仓库 git 地址 + tag) s.version必须与后面 git tag 完全一致
3. 推送源码仓库并打 tag
git add .
git commit -m "init v0.1.0"
git remote add origin https://gitee.com/<user>/my-private-sdk.git
git push -u origin main
git tag 0.1.0
git push origin 0.1.0
4. 添加 Spec 仓库
pod repo add MyPrivateSpecs https://gitee.com/<user>/my-private-specs.git
pod repo list
5. 校验 podspec
pod lib lint MyPrivateSDK.podspec --allow-warnings
# 必须看到 passed validation
6. 推送 podspec 到 Spec 远端
pod repo push MyPrivateSpecs MyPrivateSDK.podspec --allow-warnings
7. 使用方 Podfile
source 'https://gitee.com/<user>/my-private-specs.git'
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '12.0'
target 'TestApp' do
pod 'MyPrivateSDK', '~> 0.1.0'
end
pod install
8. 迭代发版流程
改代码 → 改 s.version='0.2.0' → commit → git tag 0.2.0 && git push origin 0.2.0 → pod lib lint → pod repo push
三、新增第二个私有库完整步骤(复用同一个 Spec 仓库)
前提:
MyPrivateSpecs已配置好(远端仓库有 main 分支、本地pod repo add已成功) ✅ 核心:不需要新建第二个 Spec 仓库,也不要再次执行pod repo add,只新建新组件的源码仓库
1. Gitee 网页新建【第二个组件源码仓库】
仓库名例如:MyImageLoaderSDK
- 类型:私有
- ❌ 不要勾选 README、gitignore、license,创建纯空仓库
2. 本地创建 pod 库模板
pod lib create MyImageLoaderSDK
cd MyImageLoaderSDK
- 交互选项与之前一致(iOS、语言、带 Demo、测试框架 None)
- 源码放入
MyImageLoaderSDK/Classes
3. 修改 MyImageLoaderSDK.podspec
Pod::Spec.new do |s|
s.name = 'MyImageLoaderSDK'
s.version = '0.1.0'
s.summary = '图片加载私有组件'
s.description = <<-DESC
图片加载内部私有SDK
DESC
s.homepage = 'https://gitee.com/<user>/my-image-loader-sdk'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'xxx' => 'xxx@xx.com' }
s.source = { :git => 'https://gitee.com/<user>/my-image-loader-sdk.git', :tag => s.version.to_s }
s.ios.deployment_target = '12.0'
s.source_files = 'MyImageLoaderSDK/Classes/**/*'
end
s.name必须与库名一致,s.version初始0.1.0
4. 源码推送到【新组件源码远端】并打 tag
git add .
git commit -m "init MyImageLoaderSDK v0.1.0"
git remote add origin https://gitee.com/<user>/my-image-loader-sdk.git
git push -u origin main
git tag 0.1.0
git push origin 0.1.0
5. 校验 podspec(必须)
pod lib lint MyImageLoaderSDK.podspec --allow-warnings
# 看到 passed validation 再往下
6. push podspec 到同一个私有 Spec 仓库 MyPrivateSpecs
✅ 重点:仍用之前的
MyPrivateSpecs,不要新建 spec 仓库
pod repo push MyPrivateSpecs MyImageLoaderSDK.podspec --allow-warnings
成功后远端 my-private-specs 自动新增目录:
MyImageLoaderSDK/
└── 0.1.0/
└── MyImageLoaderSDK.podspec
现在该 Spec 仓库同时管理:MyPrivateSDK、MyImageLoaderSDK。
7. 项目 Podfile 同时引入多个私有库
# 共用同一个私有 spec 源
source 'https://gitee.com/<user>/my-private-specs.git'
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '12.0'
target 'DemoApp' do
pod 'MyPrivateSDK', '~>0.1.0'
pod 'MyImageLoaderSDK', '~>0.1.0'
end
pod install
8. 其他同事电脑使用
只需执行一次即可拉取所有私有组件:
pod repo add MyPrivateSpecs https://gitee.com/<user>/my-private-specs.git
四、对话中遇到的具体问题与解决
问题 1:git remote add origin 之后 push 失败(远端仓库没建)
现象:push 报 Repository not found
原因:git remote add origin xxx.git 只是本地记录地址,远端仓库必须先建好。
解决:
- Gitee 网页先新建空仓库(不勾选任何初始化选项)
- 复制仓库 HTTPS/SSH 地址
- 再执行
git remote add origin <地址>+git push
勾选了 README 会导致
refusing to merge unrelated histories冲突,所以建仓必须纯空。
问题 2:没执行 pod repo add 也能 pod install 成功
原因:使用了另一种简易写法,完全绕过了 Spec 索引仓库:
# 简易写法:直接指向源码仓库 + tag,不需要 pod repo add
pod 'MyPrivateSDK', :git => 'https://gitee.com/<user>/my-private-sdk.git', :tag => '0.1.0'
对比:
| 写法 | 机制 | 是否需 spec 仓库 |
|---|---|---|
:git => ... , :tag => ... | 直接拉源码仓库对应 tag,绕过索引 | ❌ 不需要 |
'MyPrivateSDK', '~>0.1.0' | 走 Spec 索引查找 → 按 spec 里的 source 拉源码 | ✅ 必须 pod repo add |
pod repo add不执行也能拉取 = 你用的是:git/:tag简易方案。多组件、需版本约束~>、pod search、团队协作时才需升级到标准 Spec 方案。
问题 3:git repo MyPrivateSpecs xxx.git 报 unknown subcommand
原因:把 CocoaPods 命令误当成了 git 命令。
解决:命令是 pod repo,不是 git repo。git 本身没有 repo 子命令。
问题 4:pod repo MyPrivateSpecs xxx.git 报 Unknown command
原因:pod repo 后面缺少子命令 add。
解决:
pod repo add MyPrivateSpecs <spec仓库git地址>
# 语法:pod repo add <本地别名> <远端spec仓库url>
问题 5:An unexpected version directory 'Classes' was encountered 报错
现象:push 后本地 Spec 仓库目录出现 Classes 文件夹。
原因:Spec 仓库目录结构被破坏。正确结构只允许版本号目录:
MyPrivateSpecs/
└── MyPrivateSDK/
└── 0.1.0/
└── MyPrivateSDK.podspec # ✅ 正确
解决:
pod repo remove MyPrivateSpecs删掉本地坏仓库- 清空 Gitee 远端 my-private-specs 残留文件
- 重新
pod repo add(地址必须用 my-private-specs.git) cd MyPrivateSDK→pod lib lint→pod repo push
记住:Spec 仓库只存 podspec,绝不放 Classes 源码,源码在 my-private-sdk 仓库。
问题 6:Your configuration specifies to merge with the ref 'refs/heads/master' ... but no such ref was fetched
现象:pod repo add 后 pull 报找不到 master 分支。
原因:Gitee 远端 my-private-specs 是空仓库,没有任何分支(main/master 都不存在)。
解决(先给 Spec 远端初始化一个主分支):
# 1 删本地
pod repo remove MyPrivateSpecs
# 2 临时目录初始化并推送 main 分支到远端
mkdir tmpSpecRepo && cd tmpSpecRepo
git init
touch README.md
git add README.md && git commit -m "init spec repo main branch"
git remote add origin https://gitee.com/<user>/my-private-specs.git
git push -u origin main
# 3 Gitee 网页将默认分支设为 main
# 4 重新添加
pod repo add MyPrivateSpecs https://gitee.com/<user>/my-private-specs.git
# 5 回 SDK 目录
cd ../MyPrivateSDK
pod lib lint MyPrivateSDK.podspec --allow-warnings
pod repo push MyPrivateSpecs MyPrivateSDK.podspec --allow-warnings
main / master 都支持,关键是远端仓库至少有一个分支。临时目录用完可删。
五、命令速查表
| 操作 | 命令 |
|---|---|
| 新建库模板 | pod lib create <SDK名> |
| 校验 podspec | pod lib lint <SDK>.podspec --allow-warnings |
| 查看本地 spec 仓库 | pod repo list |
| 添加 spec 仓库 | pod repo add <别名> <spec仓库url> |
| 推送 podspec | pod repo push <别名> <podspec> --allow-warnings |
| 删除本地 spec 仓库 | pod repo remove <别名> |
| 查看远端分支 | git ls-remote https://gitee.com/<user>/my-private-specs.git |
六、高频坑点总结
- 两仓库地址混用 → Spec 仓库地址填成源码仓库,导致目录错乱/Classes 报错。
- 建仓勾选 README → 本地 push 时
unrelated histories冲突;Spec 仓库空无分支 → master 找不到。 - 命令写错 → 是
pod repo add,不是git repo,不是pod repo MyPrivateSpecs。 - 版本不一致 →
s.version与 git tag 必须严格一致,否则拉取失败。 - 路径大小写 → macOS 大小写敏感,
s.source_files路径写错会 lint 失败。 - 内网私有仓库 → 建议用 SSH 地址
git@gitee.com:<user>/xxx.git,提前配置 SSH 免密。 - pod repo push 失败排查顺序 → spec 语法 → 远端 spec 仓库权限 → tag 是否存在 → 分支是否存在。
新增私有库专项坑点
| 操作 | 是否需要新建远端 Git 仓库 |
|---|---|
| 新增一个私有组件(新 SDK) | ✅ 新建源码仓库 |
| 新增一个私有组件 | ❌ 不用新建 Spec 仓库,复用 MyPrivateSpecs |
| 组件升级版本 | ❌ 不用新建任何仓库,只需打新 tag + push spec |
新增组件时执行 pod repo add | ❌ 不需要,本地已存在 MyPrivateSpecs |
⚠️ 多个组件不能共用一个源码仓库,每个组件源码仓库必须独立。
七、快速判断用哪种方案
- 临时 / 个人 / 单组件 →
:git => ... , :tag => ...(无需维护 Spec 仓库) - 多组件 / 版本约束 / 团队协作 / pod search → 标准 Spec 仓库方案(需
pod repo add+pod repo push)
八、pod lib lint 常见警告与修复
关键认知:警告 ≠ 编译错误。
pod lib lint默认规则是「存在警告即判定校验失败」,加--allow-warnings可放行警告完成校验。正式组件建议修复核心警告,避免长期依赖--allow-warnings。
警告 1:summary: The summary is not meaningful.
- 原因:
s.summary描述过于简单(如只写"工具库")。 - 修复:填写一句简短清晰的组件功能介绍。
s.summary = "iOS 项目通用工具集合,提供字符串、日期、UI相关工具方法"
警告 2:description: The description is shorter than the summary.
- 原因:
s.description详细描述文本比摘要还短,不符合规范。 - 修复:description 内容长度必须大于 summary。
s.description = <<-DESC
iOS 项目通用工具集合,封装常用字符串处理、日期转换、设备信息、UI辅助等工具方法,内部项目使用。
DESC
警告 3:problem validating the URL(homepage 不可访问)
- 原因:CocoaPods 校验器无法访问
s.homepage地址;私有仓库最容易出现(外网访问不了私有主页/地址写错/仓库不存在)。 - 处理:
- 公开库:核对并保证地址可访问
- 私有内部库:该警告基本无法消除,可忽略,用
--allow-warnings放行
警告 4:[iOS] swift: The validator used Swift 4.0 by default because no Swift version was specified.
- 原因:podspec 未声明 Swift 版本,lint 默认按 Swift 4.0 校验。
- 修复:在 podspec 添加
s.swift_versions(OC 库也可加上,不影响 OC 代码)。
s.swift_versions = ['5.0']
修复后的 podspec 片段(综合示例)
Pod::Spec.new do |s|
s.name = 'MyProjectTool'
s.version = '1.1.0'
s.summary = 'iOS 项目通用工具集合,提供字符串、日期、UI相关工具方法'
s.description = <<-DESC
iOS 项目通用工具集合,封装常用字符串处理、日期转换、设备信息、UI辅助等工具方法,内部项目使用。
DESC
s.homepage = 'https://github.com/yourname/MyProjectTool'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'yourname' => 'xxx@xx.com' }
s.source = { :git => 'https://github.com/yourname/MyProjectTool.git', :tag => s.version.to_s }
s.ios.deployment_target = '12.0'
s.source_files = 'MyProjectTool/Classes/**/*'
s.swift_versions = ['5.0'] # 新增,修复 Swift 版本警告
end
校验命令
# 修复 podspec 后优先尝试不带 --allow-warnings
pod lib lint MyProjectTool.podspec
# homepage 链接警告依然存在(私有仓库场景)时使用
pod lib lint MyProjectTool.podspec --allow-warnings
# 看到 passed validation 即为通过
九、pod repo push 命令报错排查
报错:[!] A spec-repo name or url is required.
- 原因:
pod repo push命令语法不全,缺少「spec 仓库别名」和「podspec 文件」两个必填参数。 - 正确语法:
pod repo push 【spec仓库别名】【podspec文件】 --allow-warnings
- 示例:
# 错误(不带参数,会报 required 错误)
pod repo push
# 正确
pod repo push MyPrivateSpecs MyProjectTool.podspec --allow-warnings
- 查看本地 spec 仓库别名:
pod repo list
# 第一列就是别名,填入 push 命令
关键前置:版本号必须与源码 tag 严格一致
push 的 s.version(如 1.1.0)对应的源码仓库必须打好同名 tag 并推送到远端,否则 pod install 拉不到代码:
git tag 1.1.0
git push origin 1.1.0
appintentsmetadataprocessor相关日志只是 Xcode 编译 note,完全不用处理。
十、私有 Spec 仓库发布进阶报错与命令规范(团队已有 Spec 仓库场景)
本章适用于:公司内网已有一套私有 Spec 仓库(本地别名如
MyPrivateSpecs,具体以pod repo list结果为准),团队新增组件、打 tag 后发布时遇到的高频问题。
进阶问题 1:pod repo push 报 Unable to find the 'xxx' repo
- 现象:
pod repo push Specs XXX.podspec --allow-warnings
# [!] Unable to find the `Specs` repo. If it has not yet been cloned, add it via `pod repo add`.
- 原因:
pod repo push的第一个参数必须是本地 Spec 仓库别名(pod repo list第一列),不是远端 Git 仓库名。填了远端仓库名/远端地址都会找不到。 - 解决:
pod repo list
# 第一列就是本地别名,替换命令里的参数
pod repo push MyPrivateSpecs XXX.podspec --allow-warnings
- 要点:
- 本地别名与远端仓库名可以不一致,
pod repo add <本地别名> <远端地址>时别名可自定; - 同一内网仓库可能被加了 ssh / http 两个别名,选一个统一使用,避免后面重复 spec 警告。
- 本地别名与远端仓库名可以不一致,
进阶问题 2:pod lib lint 报 Unable to find a specification for 'XXX' depended upon by ...
- 现象:
ERROR | [iOS] unknown: Unable to find a specification for `MYDeviceLinkCore (~> 1.3.2)` depended upon by `MYDeviceInfoService`
- 原因:
pod lib lint/pod repo push默认只在官方源(trunk/CDN)查找依赖,找不到你的内网私有依赖。 - 解决:lint / push 时通过
--sources显式指定私有源 + 官方源(逗号后不能有空格):
pod lib lint --sources=MyPrivateSpecs,trunk --allow-warnings --verbose
- 补充:
MyPrivateSpecs是本地私有 spec 仓库别名(pod repo list查看),trunk是官方源;- 确保私有 spec 仓库里已 push 过对应依赖的正确版本;
- 本地 spec 太久没更新先
pod repo update MyPrivateSpecs。
进阶问题 3:ERROR | [iOS] xcodebuild: Returned an unsuccessful exit code(M 芯片 Mac 高频)
- 现象:只有 xcodebuild 返回非 0 错误码,日志只能看到依赖构建图,无直观编译报错,有时伴随
The Xcode build system has crashed。 - 常见根因:
--sources别名写错/没写私有源,找不到团队私有依赖 → 依赖解析失败 → 构建失败;- M 系列芯片模拟器架构冲突:老私有底层库不支持 arm64 模拟器架构,M 芯片编译模拟器架构直接报错(日志常见
all architectures in VALID_ARCHS are also in EXCLUDED_ARCHS); - podspec 配置缺陷:
source_files路径写错、依赖版本不匹配、tag 与s.version不一致。
- 解决步骤:
pod repo list确认别名,--sources用正确别名;- podspec 增加架构排除配置(优先只用
pod_target_xcconfig,避免user_target_xcconfig污染宿主工程):
s.pod_target_xcconfig = {
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64'
}
- 带
--verbose查看完整编译日志定位真实报错; - 指定
--platform=ios只编译真机架构绕开模拟器; - 应急调试 spec 语法可用
--skip-xcode-validation(只校验 spec,不编译代码,禁止作为上线依据)。
进阶问题 4:pod repo push 使用 --no-lint 跳过校验的规范
- 常见高频用法(本地已完整 lint 通过、只想快速入库时):
pod repo push MyPrivateSpecs XXX.podspec --allow-warnings --no-lint
--no-lint含义:推送阶段跳过内置 lint 校验,直接把 podspec 提交推送。- 优点:速度快,适合迭代发版、本地已充分验证过的场景。
- ⚠️ 风险:
- 不会校验 spec 语法、依赖是否存在、tag 是否存在、源码能否编译,错误 spec 也能入库;
- 问题会延迟到业务工程
pod install才暴露,排错成本更高; - 新人/首次发布不推荐,仅作熟手本地验证后的快速捷径。
- ✅ 强制配套流程:
# 前置必须完整编译校验通过
pod lib lint --sources=MyPrivateSpecs,trunk --allow-warnings --verbose --platform=ios
# 校验 OK 后再快速推送
pod repo push MyPrivateSpecs XXX.podspec --allow-warnings --no-lint
进阶问题 5:大量 Found multiple specifications for 'XXX' 警告
- 现象:
pod lib lint输出海量[!] Found multiple specifications for 'XXX'。 - 原因:本地同时存在两个 Spec 仓库副本指向同一个内网仓库(如一个 ssh 别名、一个 http 别名),或同时存在官方 git 源 + CDN 源,CocoaPods 找到多份相同 spec。
- 解决:
- 删除多余副本,保留一个私有源 + 一个官方源:
pod repo remove <多余别名>
pod repo list
- Podfile 里
source也不要同时写同一个私有仓库的 ssh + http 两个地址,统一保留一个。
发布命令速查(团队已有 Spec 仓库场景)
# 1 更新本地私有 spec 仓库
pod repo update MyPrivateSpecs
# 2 快速语法校验
pod lib lint --sources=MyPrivateSpecs,trunk --allow-warnings --quick
# 3 完整编译校验(上线前必须通过)
pod lib lint --sources=MyPrivateSpecs,trunk --allow-warnings --verbose --platform=ios
# 4 稳妥推送(自动 lint)
pod repo push MyPrivateSpecs XXX.podspec --sources=MyPrivateSpecs,trunk --allow-warnings --platform=ios
# 5 熟手快速推送(本地已 lint 通过再用)
pod repo push MyPrivateSpecs XXX.podspec --allow-warnings --no-lint
附录:CocoaPods 私有库高频命令速查清单
把
TeamPrivateSpec替换为你本地pod repo list查到的私有源别名;xxx.podspec替换为当前组件的 spec 文件名。
1. pod repo 私有索引仓库管理
# 查看本地所有spec仓库别名(排错首选)
pod repo list
# 添加私有Spec仓库(首次环境配置)
pod repo add TeamPrivateSpec git@xxx:iOS/Specs.git
# 更新本地私有索引(多人协作必执行)
pod repo update TeamPrivateSpec
# 删除异常仓库别名
pod repo remove TeamPrivateSpec
# 稳妥推送(自带lint校验,新版本首发)
pod repo push TeamPrivateSpec xxx.podspec --sources=TeamPrivateSpec,trunk --allow-warnings --platform=ios
# 熟手快速推送(跳过推送阶段校验)
pod repo push TeamPrivateSpec xxx.podspec --allow-warnings --no-lint
⚠️ 强制约束:使用 --no-lint 前,必须本地完整跑通 pod lib lint,避免脏 spec 入库。
2. pod lib lint 发布前校验(核心必跑)
# 轻量预检:只校验spec语法,不编译源码(速度快)
pod lib lint --sources=TeamPrivateSpec,trunk --allow-warnings --quick
# 完整编译校验(上线必须全部通过,输出详细日志)
pod lib lint --sources=TeamPrivateSpec,trunk --allow-warnings --verbose --platform=ios
# 仅校验spec结构,跳过Xcode编译(仅调试spec格式,不可用于发版)
pod lib lint --sources=TeamPrivateSpec,trunk --allow-warnings --skip-xcode-validation
参数说明
--sources=私有源,trunk:指定依赖搜索源,私有库必填,顺序不能颠倒--allow-warnings:放行警告,不会阻断错误--verbose:打印完整编译日志,排查 xcodebuild 报错神器--platform=ios:只编译 iOS 平台,排除多余平台编译--quick:轻量校验,不构建工程--no-lint:push 时跳过内置 lint 检查
3. 配套辅助命令
# 查看CocoaPods版本
pod --version
# 清理缓存(依赖拉取异常时使用)
pod cache clean --all
# 组件Demo工程更新依赖
pod install
pod update
# 发版配套:打Git版本标签
git tag 1.0.0
git push origin 1.0.0
4. 标准发布流水线(固定执行顺序)
# 1. 更新本地私有索引
pod repo update TeamPrivateSpec
# 2. 快速语法预检
pod lib lint --sources=TeamPrivateSpec,trunk --allow-warnings --quick
# 3. 完整编译校验(必须全通过)
pod lib lint --sources=TeamPrivateSpec,trunk --allow-warnings --verbose --platform=ios
# 4. 推送至私有Spec仓库(日常快速版)
pod repo push TeamPrivateSpec xxx.podspec --allow-warnings --no-lint
5. 参数速查表
| 参数 | 作用 | 使用场景 |
|---|---|---|
| --sources=A,trunk | 指定依赖源 | 私有库必加 |
| --allow-warnings | 允许警告 | 日常调试、发布 |
| --verbose | 输出详细日志 | 排查编译报错 |
| --platform=ios | 限定iOS平台 | 减少无效编译 |
| --quick | 轻量校验 | 初步检查spec格式 |
| --no-lint | 跳过push自带校验 | 本地已跑完lint后的快速发布 |