Cocoapods & Podspec 系列问题


Cocoapods官方指南

目录

1. Cocoapods工作原理
2. CocoaPods安装和更新问题
3. pod install 和pod update 区别
4. Podfile.lock和Manifest.lock
5. podspec 什么鬼
6. pod常用命令
7. CocoaPods使用中常遇问题
  -  CocoaPods已经导入第三方库,但头文件却not found


  • 使用CocoaPods组织管理后,项目会生成ProjectName.xcworkspace、Podfile.lock、Pods等文件,我们通过Podfile引入的第三方库主要由Pods工程中的Pods-ProjectName-frameworks.sh脚本负责
Pods-ProjectName-frameworks.sh

在每次编译的时候该脚本帮我们把预引入的所有三方库文件打包的成ProjectName.a静态库文件,放在我们原Xcode工程中Framework文件夹下,供工程使用

  • Resource文件:Resource资源文件主要由Pods工程中的Pods-ProjectName-resources.sh脚本负责,在每次编译的时候,该脚本会帮你将所有三方库的Resource文件copy到目标目录中。

  • 依赖参数设置:在Pods工程中的的每个库文件都有一个相应的SDKName.xcconfig,在编译时,CocoaPods就是通过这些文件来设置所有的依赖参数的,编译后,在主工程的Pods文件夹下会生成两个配置文件,Pods-ProjectName.debug.xcconfig、Pods-ProjectName.release.xcconfig。

简单理解
CocoaPods的原理是将所有的依赖库都放到另一个名为Pods的项目中,然后让主项目依赖Pods项目,这样,源码管理工作都从主项目移到了Pods项目中。Pods项目最终会编译成一个名为libPods.a的文件,主项目只需要依赖这个.a文件即可。


  • Cocoapods 安装问题集合


在项目开发中CocoaPods初次安装或者更新时,总会遇到各种问题,但是一直不清楚这些问题导致的原因,喜欢刨根问底的我们怎么能够容忍,所以还是要知道Why。

1、先通过命令$ gem sources -l查看当前你的ruby源

输出下面的 Ruby 默认源需要移除更换:
*** CURRENT SOURCES ***
https://rubygems.org/

说明:
ruby源默认是:https://rubygems.org/   这个源路径国内不能使用
所以一般使用淘宝的镜像https://ruby.taobao.org/
  1. 删除ruby默认源、添加国内支持的源
gem sources --remove https://rubygems.org/
gem sources -a https://ruby.taobao.org/

在执行gem sources -a https://ruby.taobao.org/时可能会遇到下面的问题

ERROR:  SSL verification error at depth 0: certificate has expired (10)
ERROR:  Certificate /C=CN/ST=ZheJiang/L=HangZhou/O=Alibaba (China) Technology Co., Ltd./CN=*.taobao.org expired at 2018-12-05T03:16:02Z
Error fetching https://ruby.taobao.org/:
    SSL_connect returned=1 errno=0 state=error: certificate verify failed (https://ruby.taobao.org/specs.4.8.gz)

查看资料导致该问题是因为taobao Gems 源已停止维护,现由 ruby-china 提供镜像服务,
即我们要用镜像源:http://gems.ruby-china.org

即执行 gem sources -a http://gems.ruby-china.org ,执行该命令可能会出现下面Error

Error fetching http://gems.ruby-china.org:
    bad response Not Found 404 (https://gems.ruby-china.org/specs.4.8.gz)

因为该镜像源地址可能会时常发生变化,所以遇到 Error ...404页面没找到说明源已经变了,此时就点击 http://gems.ruby-china.org 该地址进去看下当前的源变成了什么

image.png

源果然变化了,所以我们添加变化后的新源即可
即执行 gem sources -a https://gems.ruby-china.com,执行成功之后gem source -l查看一下

*** CURRENT SOURCES ***

https://gems.ruby-china.com

此时我们已经替换成新的源了

  1. 执行 sudo gem install cocoapods命令安装cocoapods
  2. cocoapods安装成功之后执行 pod setup命令
为什么要执行pod setup ??

因为所有的pod项目的 podspec文件都托管在 https://github.com/CocoaPods/Specs 这个远程索引库
第一次执行pod setup时CocoaPods会将这些podspec索引文件更新到本地的~/.cocoapods/目录下
这个索引文件比较大有 300多M左右,所以第一次更新时非常慢

如果对于索引库、podspec文件不明白的朋友可以查看这篇文章

怎样查看pod setup执行进度、解决pod setup 的慢看这篇文章


更新问题


Xcode10版本工程cocoapod <=1.5.3问题

image.png
RuntimeError - [!] Xcodeproj doesn't know about the following attributes {"inputFileListPaths"=>[], "outputFileListPaths"=>[]} for the 'PBXShellScriptBuildPhase' isa.

CocoaPods with Xcode 10 RuntimeError

解决办法:通过 sudo gem install cocoapods 重新安装也是升级cocoapods
此时一般也会遇到上面说到的问题,相应解决就ok了


  • pod install & pod update


何时使用pod install以及何时使用pod update?

pod install :

  • 第一次在工程里面使用pods的时候使用,并且每次编辑你的Podfile(添加新库、移除库、更新库)的时候使用
  • 每次运行pod install命令的时候会把你安装或者更新的每个库的版本都记录在Podfile.lock文件里面
  • Podfile.lock文件记录你每个安装库的版本号,并且锁定了这些版本。

当你使用pod install会去查看在Podfile.lock里面所列出的那些库,然后安装在Podfile.lock里面明确的版本。不会去检查该库是否有新的版本。对于还不在Podfile.lock中的库,会找到Podfile里面描述对应版本(例如:pod "MyPod", "~>1.2")。

pod update:
当你运行 pod update PODNAME 命令CocoaPods会帮你更新这个库最新版本,而不需要考虑Podfile.lock里面的限制。如果你运行pod update,后面没有跟库的名字,CocoaPods就会更新每一个Podfile里面的库到最新版本。

总结:

开发中当你在Podfile里面添加了一个Pod库的时候,你应该使用pod install,这个命令不会更新那些已经安装了的库;要更新某个库的时候你应该使用pod update PODNAME去更新某个特定的库,而不是pod update(pod update会更新所有的库)。

举例:以下会举例说明在各个场景下的使用。

场景1:User1创建了一个工程

User1创建了一个工程,并且想使用A、B、C这三个库,所以他就创建了一个含有这个三个库的Podfile,并且运行了pod intall。这样就会安装了A、B、C三个库到这个工程里面,假设我们的版本都为1.0.0。因此Podfile.lock跟踪并记录A、B、C这三个库以及版本号1.0.0。

顺便说一下:由于这个工程是第一次运行pod install,并且Pods.xcodeproj工程文件还不存在,所以这个命令也会同时创建Pods.xcodeproj以及.xcworkspace工程文件,这只是这个命令的一个副作用,并不是主要目的。

场景2:User1添加了一个库之后

User1添加了一个库D到Podfile文件中。然后他就应该运行pod install命令了。所以即使库B的开发者发布了B的一个新版本1.1.0。但只要是在第一次执行pod install之后发布的,那么B的版本仍然是1.0.0。因为User1只是希望添加一个新库D,不希望更新库B。

这就是很多人容易出错的地方,因为他们在这里使用了pod update,因为想着“更新我的工程一个新的库而已”。这里要注意!

场景3:User2加入到这个工程中

然后,User2,一个之前没有参与到这个工程的人,加入了。他clone了一份仓库,然后使用pod install命令。Podfile.lock的内容就会保证User1和User2会得到完全一样的pods,前提是Podfile.lock被提交到git仓库中。

即使库C的版本已经更新到了1.2.0,User2仍然会使用C的1.0.0版本,因为C已经在Podfile.lock里面注册过了,C的1.0.0版本已经被Podfile.lock锁住了。

场景4:检查某个库的新版本

之后,User1想检查pods里面是否有可用的更新时,他执行了pod outdated,这个命令执行后,会列出来:B有了1.1.0版本,C有了1.2.0版本。这时候,User1打算更新库B,但不更新库C,所以执行pod update B,这样就把B从1.0.0更新到1.1.0(同时更新Podfile.lock里面对B的版本记录),此时,C仍然是1.0.0版本,不会更新。

在Podfile中使用明确版本还不够

有些人认为在Podfile中明确某个库的版本

例如:pod 'A', '1.0.0' ,足以保证所有项目里面的人都会使用完全一样的版本。这个时候,他们可能会觉得,此时如果添加一个新库的时候,我使用pod update并不会去更新其它的库,因为其它的库已经被限定了固定的版本号。

但事实上,这不足以保证User1和User2的pods中库的版本会完全一样。一个典型的例子是,如果库A有一个对库A2的依赖(声明在A.podspec中:dependency 'A2', '~> 3.0'),如果这样的话,使用 pod 'A', '1.0.0' 在你的Podfile中,的确会让User1和User2都使用同样版本的库A(1.0.0).

然而:最后User1可能使用A的依赖库A2的版本为3.4(因为3.4是当时User1使用的最新版本),但User2使用的库A2版本是3.5(假设A2的开发者刚刚发布了A2的新版本3.5)。

所以只有一个方法来保证某项目的每个开发者都使用相同版本的库,就是每个电脑中都使用同样的Podfile.lock,并且合理使用pod install 和 pod update。


  • Podfile.lock & Manifest.lock是什么


当我们项目里集成了CocoaPods并第一次执行完pod install

  • 在项目根目录生成一个Podfile.lock文件 在Pods目录下生成Manifest.lock文件
  • Podfile.lock 中会指明项目当前依赖库的版本 (包括Podfile 中直接写明使用的库以及这些库依赖的其他库)

当你跟小伙伴协同开发时,小伙伴同步了你的 Podfile.lock 文件后,他执行 pod install会安装 Podfile.lock 指定版本的依赖库,这样就可以防止大家的依赖库不一致而造成问题。因此,CocoaPods 官方强烈推荐把 Podfile.lock 纳入版本控制之下。

注意:Podfile.lock 并不是一成不变的

当你修改了 Podfile 文件里使用的依赖库或者运行pod update 命令时,就会生成新的 Podfile.lock 文件。


Podfile.lock 主要包含以下几部分


PODS:
  - YYModel (1.0.4)

DEPENDENCIES:
  - YYModel

SPEC CHECKSUMS:
  YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30

PODFILE CHECKSUM: 65f13d3af89ad0d2828bfc5b5919652fb43376fc

COCOAPODS: 1.4.0

协同开发时注意使用 pod installpod update 的区别:

使用pod install

只会安装 Podfile 中新改变的东西
并且会:优先遵循 Podfile 里指定的版本信息
其次遵循 Podfile.lock 里指定的版本信息来安装对应的依赖库

比如:
在Podfile里没指定AFN的版本,但Podfile.lock 里指定了AFN 版本是 3.0.1,那么即使现在有最新的 3.0.4,最终也会安装3.0.1

但如果Podfile里指定了AFN版本是3.0.3则会安装 3.0.3,并更新Podfile.lock里的版本信息

使用pod update

根据Podfile的规则更新所有依赖库
不会去看Podfile.lock,而是根据安装依赖库的情况生成新的 Podfile.lock文件


Manifest.lock 又是啥?


  • Manifest.lock 相当于 Podfile.lock 的副本
  • 执行pod install后在Pods目录下生成Manifest.lock文件
  • Build时会执行 Build Phases 中的[CP] Check Pods Manifest.lock 脚本检查一下 Podfile.lock 和 Manifest.lock 是否一致,如果不一致就会报错
image.png


问:既然有了Podfile.lock那为啥还要有Manifest.lock?


这样做的原因是 Pods 目录并不总是被放到版本控制之下,有了这个检查机制就能保证开发团队的各个小伙伴能在运行项目前更新他们的依赖库,并保持这些依赖库的版本一致,从而防止在依赖库的版本不统一造成程序在一些不明显的地方编译失败或运行崩溃。


问:Podfile.lock报版本找不到问题或版本不一致问题?


场景1:

协同开发时有天一个小伙伴升级了Podfile中某个库的版本并提交到远程(比如AFN从3.0.1升级到了3.0.4),然后你更新了之后执行了pod install... 然后爆红了

场景2:

团队小伙伴开了一个私有库A,我们项目里只是指定了 pod A但是没有指明版本,此时A小伙伴将A库的进行了优化更新了版本1.1.1并提及到了远程代码仓库;当我们更新并执行pod install时会先查看Podfile.lock 里指定的A库的版本,然后CocoaPods会查看Podfile.lock 里指定的A库的版本是否和我们本地索引库里A库的版本是否一致,不一致然后爆红

场景...

当你更新代码执行pod install爆红
可能是你本地的Podfile.lock里库版本 和远程服务器上的Podfile.lock的库版本不一致时;
可能是你本地索引库里库的版本和Podfile.lock里指定的库的版本不一致

根据具体情况可以参考一下解决方法

  • 删掉.lock文件再pod install一次,如果仍然报错
  • 执行 pod repo update 更新本地索引库 就是本地CocoaPods的spec资源配置信息;如果不知道本地索引库是什么可以参看这篇文章里面说的很清楚 ,然后在执行pod install

比如下面的报错问题:直接 pod repo update之后在pod install 完美解决

image.png

怎么对待 Podfile.lock

以下建议可供参考:

  • Podfile.lock 应该加入版本控制,保证小伙伴们的依赖库版本一致,防止出现难以发现的 bug
  • 在初始创建项目的时候就建议加入版本控制
  • Podfile 中最好指定明确的依赖库版本
  • 明白 pod install 和 pod update 的区别以及它们对 Podfile.lock 的影响,合理使用


pod命令


创建默认的 Podfile

$ pod init

第一次使用安装pod库

$ pod install

安装pod库,不更新本地索引,速度快,但是不会升级本地代码库

$ pod install --no-repo-update 

升级所有pod库

$ pod update

更新pod库,不更新本地索引,速度快
可以安装新pod库或者删除不用的pod库,但是不会升级项目已经安装的pod库

$ pod update --no-repo-update 

查看哪些pod库有更新版本,如果习惯使用 --no-repo-update 参数,这个命令就显得格外重要了

$ pod outdated

搜索pod库

  • 空格 下一页
  • q 退出
  • / 搜索
$ pod search AFNetworking

只搜索复合名字的pod库,这个对于搜索结果非常多时,尤其有用

$ pod search AFNetworking --simple

帮助

$ pod --help

Podspec 文件

关于Podspec文件详细说明,可以参看这篇文章 - Podspec语法参考 v1.2.0.beta.1


  • Cocoapods使用中常见问题


Q1: Cocoapods导入第三方库,但头文件却显示没有发现

方案一

Product -> Clear Build Folder (按住option) 清理一下,重新Build一次

方案二

选择Target -> Build Settings 菜单,找到\”User Header Search Paths\”设置项
新增一个值"${SRCROOT}",并且选择\”Recursive\” 

方案三 看Q2中的方式

Q2: 如果我们的开源库依赖系统库怎么办?

# s.framework = 'AAAFramework'// 去掉#,设置依赖的系统库名称
# s.frameworks = 'AAAFramework', 'BBBFramework'//设置多个系统库名称
 
# s.library = 'iconv'// 设置只依赖一个系统的library
# s.libraries = 'iconv', 'xml2' // 设置依赖多个系统的library
 
# s.xcconfig = { 'HEADER_SEARCH_PATHS' => '$(SDKROOT)/usr/include/libxml2' }// 这里是工程配置,这样使用者就不需要手动处理,由pod自动处理了,也是Q1中问题的一种解决方法。

比如我们自己的开源库依赖 SystemConfiguration.framework,AVFoundation.framework,CoreTelephony.frameworklibc++.tbdlibxml2.tbdlibsqlite3.0.tbd 这几个系统库,就可以在podspec文件中指定如下:

s.frameworks = 'SystemConfiguration', 'AVFoundation', 'CoreTelephony'
s.libraries = 'c++', 'sqlite3.0', 'xml2'
s.xcconfig = { 'HEADER_SEARCH_PATHS' => '$(SDKROOT)/usr/include/libxml2' }

Q3: 如果我们的开源库依赖其他第三方静态库?

s.vendored_frameworks = 'Framewroks/*.framework'  // 注意这里指定的路径
s.vendored_libraries = 'Framewroks/*.a'

因为.framework和.a静态库都存放在Framewroks这个文件夹下,该文件夹和.podspec文件在同级目录,所以上面的路径指定就是 Framewroks/*.framework,实际路径需要根据你存放静态库的路径来指定

WX20190711-142107@2x.png

Q4: Bundle资源的依赖

s.resource_bundles = {
    'AAASDK' => ['Framewroks/Resources/AAASDK.bundle'],
    'BBBSDKLib' => ['Framewroks/Resources/BBBSDK.bundle']
}

Q5: 关于Pod子库的制作可以参看这篇文章subspec子库的制作

参看文档

CocoaPods工作原理及使用中遇到的问题

pod install vs. pod update
使用 pod install 还是 pod update ?
关于 Podfile.lock 带来的痛-这篇文章讲述的很
Podfile语法参考-官方指南
# Cocoapods的使用教程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容