Xcode项目引入Cocoapods管理(基础篇)

项目组件化、平台化是技术公司的共同目标,越来越多的技术公司推崇使用pod管理第三方库以及私有组件,一方面使项目架构更加清晰,一方面现有的工具Cocoapods提供了近乎完美的解决方案。这里我们来讨论一下如何在Xcode 工程中集成Cocoapods,这里提供入门级别的集成和进阶集成方式。

本文目录

Cocoapods简介

Cocoapods是OS X和iOS下的一个第三方库管理工具,并且支持Objective-C和swifit语言。通过Cocoapods为项目添加称为"Pods"的依赖库(这些库必须是Cocoapods所支持的),并且轻松实现第三方库的版本管理。

引入Cocoapods的意义:

Cocoapods在引入第三方库时自动为我们完成各种配置,包括配置编译阶段、连接器选项、甚至是ARC环境下的-fno-objc-arc配置等

Cocoapods可以很方便的查找第三方库,可以快速方便的寻找到优秀的第三方库以及它们的各种信息。

Cocoapods 官方网站:

https://cocoapods.org/

Cocoapods整个项目托管在github上, 所有的Pods依赖库也都依赖github

https://github.com/CocoaPods

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错误。对于这个问题,估计有多种可行的方案:

  1. 方案一:给金融模块提供 AFNetworking.a 而不是 AFNetworking.framework。
  2. 方案二:金融模块打framework时剔除AFNetworking ,在其打成framework时不勾选 AFN相关文件。(这种方式通过检验,因为金融模块不需要 link AFNetworking.framework)。
  3. 方案三:暂未定

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集成时间表
  1. 将原来的手动添加的第三方库迁移到现在的Cocoapods管理第三方库,需要将原来第三方库的配置相关的文件删除干净。Cocoapods会将第三方库的所有需要配置的静态库或者文件集成在libPods.a静态库中,在Build Phases中可以找到这个.a静态库。鉴于这个考虑,我们需要删除原来手动添加的第三方库的配置文件。

  2. 纪录所有的原来的第三方库的配置文件,一并删除

  • AFNetworking
  • FLEX
  • FMDB
  • ...
Cocoapods常见问题汇总
  1. Pods依赖库已经更新

  2. Cocoapods无法安装的问题。

Mac系统升级到10.11使用Cocoapods出现pod:command not found 解决方案

$ sudo gem install -n /usr/local/bin cocoapods

如果podupdate 或者pod install 还卡在哪儿,则

  1. pod install 或者pod update 速度慢的问题
查看ruby源,更换为淘宝镜像,如果还出现问题,则
原因可能是:当执行以上两个命令时会升级Cocoapods的Specs仓库,加一个参数就可以省略这一步,然后速度可能会提升。参数命令如下:
pod install --verbose --no-repo-update
pod update --verbose --no-repo-update 
执行完命令以后有时还是会报错,不妨更新一下本地repo
pod repo update 
  1. 这个问题是比较常见的问题
"podfile.lock" not such file or directory......

http://*.com/questions/17072396/cocoapods-errors-on-project-build

  1. 集成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.

  1. 需要加入gitignore的文件:

  2. 对MyApp包大小的影响、对编译时间和编译速度的影响

  3. 如何更新第三方库

  4. 第三方库与项目代码中的文件重名冲突

  5. 第三方库的sdk版本与项目sdk版本不符时解决方案

  6. Cocoapods软件版本更新

  7. Cocoapods 目前版本为 0.39.0, 最新的1.0.0为测试版

  8. 当两个库同时需要使用AFNetworking时,Cocoapods会确定一个同时能被这两个库使用的版本,然后将同一个安装版本链接到两个不同的库中。

  9. 安装pod install 第三方库过程中,Cocoapods会使用递归来分析所有的需求,并且建立一个代码相关性的图,最后将Podfile序列化为Podfile.lock

  10. 选择的文件夹对:

Could not automatically select an Xcode project. Specify one in your Podfile like so: xcodeproj 'path/to/Project.xcodeproj'

问题出在你选择的项目文件夹不对,应该选择Iphone文件夹集成Cocoapods

  1. 如果项目中有与Pod同名的文件。编译不会通过。

  2. 对于那些不在Cocoapods公共Git仓库中的库,可以用任何一个Git,Mercurial或者是SVN仓库取代,并且还可以指定具体的commit,branch或者tag。 即私有pod。

pod 'Y', :git => 'https://github.com/NSHipster/Y.git', :commit => 'b4dc0ffee' 
  1. over.

 

上一篇:C++程序代码的内存结构分析


下一篇:cocos2dx在xcode上编译错误解决方案