接上文SVN+Cocoapods, 使用SVN存放Specs索引库有一个致命缺陷,如果开发组件库的过程中又在podspec
文件里使用dependency依赖了其他私有库, 那么之后在使用pod package
打包时会报错无法找到依赖的私有库。这是因为pod package
默认搜索官方索引库, 而且手动指定–spec-sources
并不支持SVN路径。
为解决打包问题,代码依旧托管到SVN,改将Specs索引库托管到第三方Git。 详细操作流程见下文。
创建远程私有库
这里使用码市(https://coding.net)建立远程私有库。注册账号并新建项目:
绑定远程私有库
要让pod search
也能搜索到我们自己开发的组件库, 与cocoapods官方的公有索引库原理类似, 也需要将刚刚创建的远程私有库同步到本地, 打开终端, 输入:
pod repo add ComponentSpecsGit https://git.coding.net/mangox/ComponentSpecs.git
命令格式为:
pod repo add 本地私有库名称 远程私有库地址
同步完成后, 输入以下命令查看本地所有的cocoapods索引库:
pod repo
结果如图:
更多私有库相关介绍参见官方文档:Private Pods
创建SVN代码目录
SVN代码托管目录如图:
目录说明如下:
- dev: 组件库源码开发目录, 在此目录下进行源码开发, 以及开发完成后的打包工作;
- trunk:用于组件库发布, 此目录下的工程只引用dev打包的framework, 不涉及源码;
- tags:组件库拉取目录,保存组件库的各个版本,供组件使用者拉取使用;
具体每个目录的使用详见后文。
创建本地组件
使用下面的命令创建一个登录组件:
pod lib create XBLoginUIModule
如图, 可按照个人开发需求对组件进行配置:
由于这里使用SVN进行代码管理,而通过上面命令下载的pod模板时实际上使用的是git, 建议删除掉以下三个隐藏文件:.git
,.gitignore
和.travis.yml
。 并将项目目录调整为下图所示:
创建完成后,将XBLoginUIModule目录整体提交到SVN。
更多pod lib create
介绍参见官方文档Using Pod Lib Create
编辑podspec
打开dev
目录下的XBLoginModule.podspec
文件,推荐使用Sublime Text
,右下角选择语言为Ruby
,会出现语法高亮效果。
这里对几个关键配置进行编辑说明:
1 | Pod::Spec.new do |s| |
编辑完成后,将改动提交到SVN。
更多podspec介绍参见官方文档:Podspec Syntax Reference
安装本地组件依赖
在开始具体的组件库开发之前,需要对Example工程安装pod依赖。
cd到Example
目录下, 执行:
pod install
此时会出现一个错误:
这是因为我们在podspec文件中依赖了私有库XBHTTPService
, 因此在使用时需要告诉pod在哪个地方拉取我们已开发完成的私有库。
打开Podfile
文件, 在最上部添加两行:
source 'https://github.com/CocoaPods/Specs.git'
source 'https://git.coding.net/mangox/ComponentSpecs.git'
上面的代码指定了pod的索引库地址,前者是cocoapods公有库, 后者是我们自己建立的私有库。
然后重新执行pod install
, 会报错:
这是由于私有库XBHTTPService
被打包成了一个静态库,继续打开打开Podfile
文件,在指定sources之后添加:
1 | pre_install do |installer| Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {} |
注意, 上面的代码根据cocoapods版本不同略有差异,上述写法针对cocoapods 1.3.1或以上版本。
再次执行pod install
, Pod installation complete!
开发本地组件
打开XBLoginUIModule.xcworkspace
, 查看到在podspec文件中指定的依赖, Command+B
编译, 如果出现错误的话可能是上面的某个步骤出现了问题, 可以根据错误描述进行修改。
本地组件的开发是在Pods工程下的Development Pods目录下进行, 删除自带的ReplaceMe.m
文件, 然后在目录下新建文件进行开发。
注意,每次只要修改了podspec文件,都必须cd到Example目录下执行命令: pod update
。
校验本地组件
开发完成后,将本地dev目录提交到SVN,然后cd到dev目录下, 执行命令:
pod spec lint XBLoginUIModule.podspec --sources=https://github.com/CocoaPods/Specs.git,https://git.coding.net/mangox/ComponentSpecs.git --use-libraries
参数sources指定索引库地址, 参数–use-libraries表明依赖的库中包含静态库, 另外, 还可以加上参数--allow-warnings
忽略警告, 否则存在任何warning的话也无法通过校验。
打包本地组件
通过校验之后, 可以将本地组件打包为framework。此时,需确保dev目录下所有改动均已提交到SVN。
cd到dev目录下, 执行命令:
pod package XBLoginUIModule.podspec --no-mangle --spec-sources=https://git.coding.net/mangox/ComponentSpecs.git,https://github.com/CocoaPods/Specs.git --force --exclude-deps
参数–no-mangle表明本地组件依赖了静态库, 参数–spec-sources指定索引库地址, –force表明强制覆盖上一次打包生成的文件(同版本), –exclude-deps表明不包含所依赖的符号库,可以减少framework的大小,不加此参数的话如果主工程引入了多个私有库,会抛出duplicate symbol
错误。
打包完成后, 可以在dev目录下找到XBLoginUIModule.framework
,如图所示:
发布本地组件(framework)
要以framework的形式发布本地组件, 首先需要在trunk目录下使用pod lib create
命令创建一个同名的组件库。 然后将上面打包好的framework复制到trunk->XBLoginUIModule目录下,
并删除掉默认添加的ReplaceMe.m
,最终目录结构如图所示:
trunk下的podspec文件大部分与dev目录下相同,不同处参见注释:
1 | Pod::Spec.new do |s| |
别忘了,要想使用Example工程还需要在Podfile中加入:
1 | source 'https://github.com/CocoaPods/Specs.git' |
cd到Example目录下, 执行pod update
命令, 这里其实可以加上--no-repo-update
参数避免每次检测cocoapods的同步。
编译Example工程, 编译成功说明没有错误可以发布了, 提交trunk目录改动到SVN。
在SVN中在trunk的基础上打出与podspec中版本号相同的tag:
tag完成后,cd到trunk目录下,执行命令:
pod repo push ComponentSpecsGit XBLoginUIModule.podspec
发布成功后可以在之前coding.net上建立的索引库中看到。
使用已发布的组件
发布完成后, 可以通过pod search
命令搜索刚刚发布的私有组件库:
如果提示:
[!] Unable to find a pod with name, author, summary, or description matching `XBLoginUIModule`
可以使用命令清除cocoapods索引文件后重新尝试:
rm ~/Library/Caches/CocoaPods/search_index.json
其他常见问题
加载资源bundle
如果开发的私有库中使用了xib或者图片资源, 开发时(dev目录)就需要在podspec文件中指定:
1 | #项目资源文件地址 |
cocoapods会在framework内建立一个XBLoginUIModule.bundle
, 包含引入的xib和图片资源。
开发完成并打包后的framework结构如图:
这里明明是存在我们打包包含的bundle资源文件的,然而在实际运行Example项目(trunk目录)时,查看下图所示目录:
bundle消失了!!!, 这是如果尝试使用bundle的xib文件, 会直接crash。
要解决这个问题, 可以将framework中的bundle文件复制到framework同级目录下:
然后编辑podspec文件,增加如下配置:
1 | # 再次引入资源包, 否则系统不会将framework内部的bundle实际拷贝到项目中 |
再次执行pod update
, bundle成功引入项目。
非ARC文件
在实际开发私有库的过程中可能会遇到单独指定某个文件为MRC的情况,可以通过建立subspec的方式解决:
1 | #这里可以不指定.h文件 |
效果如图:
其中GTMBase64.m
已经被指定为-fno-objc-arc
。
symbol not found
如果开发私有库的过程中依赖或使用了第三方的静态库, 运行Example工程时可能会出现symbol找不到的情况, 打开Pod工程的Build Settings
, 修改Mach-O Type
为Static Library
。