项目组件化、平台化是技术公司的共同目标,越来越多的技术公司推崇使用pod管理第三方库以及私有组件,一方面使项目架构更加清晰,一方面现有的工具Cocoapods提供了近乎完美的解决方案。这里我们来讨论一下如何在Xcode 工程中集成Cocoapods,这里提供入门级别的集成和进阶集成方式。
本文目录
Cocoapods简介
Cocoapods是OS X和iOS下的一个第三方库管理工具,并且支持Objective-C和swifit语言。通过Cocoapods为项目添加称为"Pods"的依赖库(这些库必须是Cocoapods所支持的),并且轻松实现第三方库的版本管理。
引入Cocoapods的意义:
Cocoapods在引入第三方库时自动为我们完成各种配置,包括配置编译阶段、连接器选项、甚至是ARC环境下的-fno-objc-arc配置等
Cocoapods可以很方便的查找第三方库,可以快速方便的寻找到优秀的第三方库以及它们的各种信息。
Cocoapods 官方网站:
Cocoapods整个项目托管在github上, 所有的Pods依赖库也都依赖github
Cocoapods发展背景
Cocoapods创建于2011年,目前Cocoapods团队有17位核心开发人员以及多达5000多个开源项目。Cocoapods的存在为代码分发提供了非常便捷的解决方案。
Cocoapods核心组件
Cocoapods是用Ruby写的,所以在安装时有时要更新ruby源。Cocoapods在解析过程中最重要的几个包的路径分别是:CocoaPods/CocoaPods、 CocoaPods/Core和 CocoaPods/Xcodeproj,其中Core提供了CocoaPods相关文件,主要是podfile和podspecs。
podfile:该文件用于配置项目所需的第三方库,可以被高度订制。
podspec:该文件描述一个库如何被加入到工程文件中。.podspec文件可以标识该第三方库所需要的源码文件、依赖库、编译选项,以及其他的第三方库所需的配置。
over.
Cocoapods与项目sdk化
有些项目处于某些模块采取的是将该业务代码打成framework,如比较重要的金融支付模块。我们在集成私有Pod过程中,将
AFNetworking
这种第三方库用用Cocoapods管理,其实是打成了.a
,而金融sdk仍然使用framework,打成.framework
,因此二者无法链接,在Link阶段报错。解决方案是,要么将金融打成.a
,要么在金融打成sdk时不勾选AFNetworking
。
gitmodule的关系与解决方案
子模块和Cocoapods都是试图解决同样的问题。使用子模块的业务准备迁移到Cocoapods 首先需要解耦,模块间解耦。
安装和使用Cocoapods
CocoaPods安装步骤
- 升级Ruby环境,更新gem 源**
终端输入:$sudo gem update --system
ps:国内需要切换源
- 安装CocoaPods要访问cocoapods.org,该网站已经被天朝墙壁,需要更换镜像来安装(淘宝镜像已经停止更新)
1、gem sources --removehttps://rubygems.org/
2、gem sources -a https://gems.ruby-china.org/
3、gem sources -l
- 安装Cocoapods
sudo gem install cocoapods
- 启动Pod
$pod setup
Pod 常用命令
Pod创建Podfile文件有一下几个步骤:
- pod 常用命令
搜索类库 pod search AFNetworking 更新第三方库: pod update导入第三方库: pod install 可以删除podfile中某个库的代码,然后: pod install 删除第三方库 :pod uninstall 查看Cocoapods版本: pod --version 查找第三方库: pod search AFNetworking
- $ cd 到工程文件目录,然后创建Podfile文件
$ touch Podfile(创建Podfile文件)
- $ vim Podfile编辑该文件,然后通过wq保存(具体可参考vim命令行)
platform :ios, '7.0' inhibit_all_warnings! pod 'SDWebImage', '3.7.3' pod 'SSZipArchive', '1.0.1' pod 'JSPatch', '0.1.5' pod 'TMCache', '2.1.0' pod 'FLEX', '2.2.0'
配置成功后执行命令
$ pod install
- 项目新增四个文件, Podfile、Podfile.lock、.xcworkspace、podfilelock.manifest以后就可以使用Pod来管理自己的组件库,
- 以后打开后缀名为 .xcworkspace文件打开工程
pod语义化版本规范
pod 'AFNetworking' // 不显式指定依赖库版本,表示每次都获取最新的版本 pod 'AFNetworking', '2.0' //只使用2.0版本 pod 'AFNetworking', '> 2.0' //使用高于2.0的版本 pod 'AFNetworking', '>= 2.0' //使用大于或等于2.0的版本 pod 'AFNetworking', '< 2.0' //使用小于2.0的版本 pod 'AFNetworking', '<= 2.0' //使用小于或等于2.0的版本 pod 'AFNetworking', '~> 0.1.2' //使用大于等于0.1.2但小于0.2的版本 pod 'AFNetworking', '~>0.1' //使用大于等于0.1但小于1.0的版本 pod 'AFNetworking', '~>0' //高于0的版本,写这个限制和什么都不写是一个效果,都表示使用最新版本
over.
Podfile与多target
Podfile本质上是用来描述Xcode工程中的targets用的。如果我们不显式指定Podfile对应的target,Cocoapods会创建一个名为default的隐式target,会和我们工程中的第一个target对应。换句话说,如果在Podfile中没有指定target,那么只有工程中的第一个target能够使用Podfile中的描述的Pods依赖库。根据需要,给不同的target指定Pods依赖库。
- 例如,名称为MyApp的target和MyPro app的target都需要Reachabilitiy、SBJson、AFNetworking三个Pods依赖库,可以使用link_with关键字来实现,将Podfile写成如下形式:
link_with 'MyApp', 'MyApp pro' platform :ios pod 'Reachability', '~> 3.0.0' pod 'SBJson', '~> 2.6.0' platform :ios , '7.0' pod 'AFNetworking'
- 不同的target使用完全不同的Pods依赖库
CocoaPodsTest这个target使用的是Reachability、SBJson、AFNetworking三个依赖库,但Second这个target只需要使用OpenUDID这一个依赖库,这时可以使用target关键字,Podfile的描述方式如下:
target :'MyApp' do platform :ios pod 'Reachability', '~> 3.0.0' pod 'SBJson', '~> 4.0.0' platform :ios, '7.0' pod 'AFNetworking', '~> 2.0' end target :'MyApp pro' do pod 'OpenUDID', '~> 1.0.0' end
- over
主App link Pods库
在集成Cocoapods后,主App可以编译通过,但是无法link到Pods 库的情况。首先,我们看一下主App是如何引入Pods中的项目,编译没有问题,关键在于link。
Cocoapods与持续集成
集成Cocoapods后对项目的持续集成的影响。项目采用OClint进行持续集成,集成Cocoapods之后,该将哪些文件加入到持续集成中。
Cocoapods与项目SDK化
MyApp项目中集成了Cocoapods,使用Cocoapods管理第三方库公共库,类似AFNetworking、MJExtension等,同时使用私有Pod管理MyFoundation等私有组件。并且建立私有Pod管理单品类业务。因此主App中Pods分为三部分:
- 开源第三方库
- MyApp私有组件库(Foundation、Catogery等)
- 单品类业务(MyApp主要涉及酒店模块、机票模块等)
对于这几部分,Cocoapods会将Pods打成libPods.a,独立模块供主App使用。
遇到的一个问题是,因为项目中存在金融模块的SDK(部分模块已经SDK化),而金融业务代码用到了AFNetworking,金融业务代码使用AFNetworking的方式是,主App给金融SDK一个AFNetworking的framework,金融使用该framework后可以调试相关代码,但是在金融打成framework给主App时不勾选AFNetworking这个target。因此具体的是:
金融SDK -->link --> 主App AFNetworking(AFN手动导入主App).
到目前为止,没有导致任务问题。
然后如果集成Cocoapods后,AFNetworking放在Pods中管理,而Pods被Cocoapods打成了podlib.a,.a与.framework的访问就会出问题, .framework无法link到.a里的AFNetworking,最终导致link错误。对于这个问题,估计有多种可行的方案:
- 方案一:给金融模块提供 AFNetworking.a 而不是 AFNetworking.framework。
- 方案二:金融模块打framework时剔除AFNetworking ,在其打成framework时不勾选 AFN相关文件。(这种方式通过检验,因为金融模块不需要 link AFNetworking.framework)。
- 方案三:暂未定
over。
Cocoapods与App打包
目前我们App提供三种打包方式,第一是Xcode打包,第二是ipa_genator.sh脚本打包,第三是测试用jenkins打包。集成Cocoapods后,这三种打包方式相关配置需要更改,否则不支持打包或者打包失败。
- Xcode打包,只需要使用MyApp.xcworkspace来编译运行程序,就可以打包成功。
- 脚本打包,需要更改相关配置,更改如下:
#config.cfg文件为脚本打包路径配置文件,之前的路径指向的是MyApp.xcodeproj,我们需要将PROJECT_NAME改为: PROJECT_NAME="MyApp.xcworkspace" #因为每次打包需要首先build,而项目集成Cocoapods后,build路径是xcworkspace而不是原来的xcodeproj,因此需要指定正确的路径。
#其次,我们需要将ipa_generator.sh文件中的 PROJ_EXT=".xcodeproj" #此处改为 PROJ_EXT=".xcworkspace" xctool_archive() { xctool -project $1 \ # 此处改为xctool -workspace -scheme $2 \ -reporter json-compilation-database:compile_commands.json \ -sdk iphoneos \ archive \ -archivePath $3 } xcodebuild_archive() { xcodebuild -project $1 \ # 此处改为xctool -workspace -scheme $2 \ -sdk iphoneos \ archive \ -archivePath $3 \ | tee xcodebuild.log }
over.
- jenkins打包失败的问题。
-
Cocopods集成时间表
将原来的手动添加的第三方库迁移到现在的Cocoapods管理第三方库,需要将原来第三方库的配置相关的文件删除干净。Cocoapods会将第三方库的所有需要配置的静态库或者文件集成在libPods.a静态库中,在Build Phases中可以找到这个.a静态库。鉴于这个考虑,我们需要删除原来手动添加的第三方库的配置文件。
纪录所有的原来的第三方库的配置文件,一并删除
- AFNetworking
- FLEX
- FMDB
- ...
Cocoapods常见问题汇总
Pods依赖库已经更新
Cocoapods无法安装的问题。
Mac系统升级到10.11使用Cocoapods出现pod:command not found 解决方案
$ sudo gem install -n /usr/local/bin cocoapods
如果podupdate 或者pod install 还卡在哪儿,则
- pod install 或者pod update 速度慢的问题
查看ruby源,更换为淘宝镜像,如果还出现问题,则 原因可能是:当执行以上两个命令时会升级Cocoapods的Specs仓库,加一个参数就可以省略这一步,然后速度可能会提升。参数命令如下: pod install --verbose --no-repo-update pod update --verbose --no-repo-update 执行完命令以后有时还是会报错,不妨更新一下本地repo pod repo update
- 这个问题是比较常见的问题
"podfile.lock" not such file or directory......
http://*.com/questions/17072396/cocoapods-errors-on-project-build
- 集成Cocoapods编译通过但是链接不通过的问题。
Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_AFNetworking", referenced from: objc-class-ref in HJCXMPPTools.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
小编发现,小编之前是手动导入的AFNetworking这个第三方库,小编估计是手动导入时更改了某些配置文件导致与Cocoapods集成时的配置文件发生冲突,导致无法link。于是小编在此用Cocoapods更新框架时,发现终端的一段警告:
[!] The `myQQ [Debug]` target overrides the `OTHER_LDFLAGS` build setting defined in `Pods/Target Support Files/Pods/Pods.debug.xcconfig'. This can lead to problems with the CocoaPods installation - Use the `$(inherited)` flag, or - Remove the build settings from the target.
这下的思路应该是,手动导入AFN时修改了某些配置,修改了Other Linker Flags。
所以解决方案是:
按照提示,在Build setting里的Other Linker Flags增加$(inherited)。喜大普奔,这个错误算是解决了。
over.
需要加入gitignore的文件:
对MyApp包大小的影响、对编译时间和编译速度的影响
如何更新第三方库
第三方库与项目代码中的文件重名冲突
第三方库的sdk版本与项目sdk版本不符时解决方案
Cocoapods软件版本更新
Cocoapods 目前版本为 0.39.0, 最新的1.0.0为测试版
当两个库同时需要使用AFNetworking时,Cocoapods会确定一个同时能被这两个库使用的版本,然后将同一个安装版本链接到两个不同的库中。
安装pod install 第三方库过程中,Cocoapods会使用递归来分析所有的需求,并且建立一个代码相关性的图,最后将Podfile序列化为Podfile.lock
选择的文件夹对:
Could not automatically select an Xcode project. Specify one in your Podfile like so: xcodeproj 'path/to/Project.xcodeproj'
问题出在你选择的项目文件夹不对,应该选择Iphone文件夹集成Cocoapods
如果项目中有与Pod同名的文件。编译不会通过。
对于那些不在Cocoapods公共Git仓库中的库,可以用任何一个Git,Mercurial或者是SVN仓库取代,并且还可以指定具体的commit,branch或者tag。 即私有pod。
pod 'Y', :git => 'https://github.com/NSHipster/Y.git', :commit => 'b4dc0ffee'
- over.