专栏首页落影的专栏CocoaPod知识整理

CocoaPod知识整理

前言

Pod库是很重要的组成部分,大部分第三方库都是通过CocoaPod的方式引入和管理,同时项目中的部分功能也可以用Pod库来做模块化。 本文是对CocoaPod的一些探究。 XS项目中的Pod库是很重要的组成部分,目前阅读器模块正在进行SDK化,需要用Pod库来管理,同时未来会做一些模块化的功能,同样需要用Pod库来处理。 本文对CocoaPods的一些内容进行探究。

正文

CocoaPods是为iOS工程提供第三方依赖库管理的工具,用CocoaPods可以更方便地管理第三方库:把依赖库统一放在Pods工程中,同时让主工程依赖Pods工程。Pods工程的target是libPods-targetName.a静态库,主工程会依赖这个.a静态库。 (下面会详细剖析这个处理过程)

CocoaPods相比手动引入framework或者子工程依赖的方式,有两个便捷之处:

  • 所有Pod库集中管理,版本更新只需Podfile配置文件;
  • 依赖关系的自动解析;

同时CocoaPods的使用流程很简单:(假设已经安装CocoaPods) 1、在xcodeproj所在目录下,新建Podfile文件; 2、描述依赖信息,以demo为例,有AFNetworking和SDWebImage两个第三方库:

target 'LearnPod' do
        pod 'AFNetworking'
        pod 'SDWebImage'
end

3、打开命令行,执行pod install ; 4、打开生成xcworkspace,就可以继续开发;

一、Podfile的写法

1、普通的写法; pod 'AFNetworking' 或者 pod 'AFNetworking', '3.2.1',前者是下载最新版本,后者是下载指定版本。

2、指向本地的代码分支;

pod 'AFNetworking', :path => '/Users/loyinglin/Documents/Learn/AFNetworking'

指向的本地目录要带有podspec文件。

3、指定远端的代码分支;

pod 'AFNetworking', :git => 'https://github.com/AFNetworking/AFNetworking.git', :branch => 'master'

指向的repo仓库要带有podspec文件。

4、针对特定的configurations用不同的依赖库

`pod 'AFNetworking', :configurations => ['Release']`

如上,只有Release的configurations生效;(同理,可以设置Debug)

5、一些其他的feature

优化pod install速度,可以进行依赖打平:将pod库的依赖库明确的写在Podfile,主端已经提供对应的工具

`require "bd_pod_extentions"`

`bytedanceAnalyzeSpeed(true)`

`bd_use_app('toutiao','thirdParty','public')`

post install的脚本,修改安装后的Pod库工程中的target设置;同理,可以修改其他属性的设置。

post_install do |installer_representation|
    installer_representation.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO'`
        end
   end
end

类似的还有pre_install的脚本;(但是install之前可能都没有pods_project,所以用处也比较少;具体的参数意义可自查,以pods_project为例

puts只有在添加--verbose参数可以看到,Pod::UI.puts则是全文可见。

pre_install do |installer|
    puts "pre install hook"
    Pod::UI.puts "pre install hook puts"
end

Podfile还可以设置一些警告提示的去除,第一行是去掉pod install时候的警告信息,第二行是去掉build时候的警告信息。

# 去掉pod install时候的警告信息
install! 'cocoapods', :warn_for_multiple_pod_sources => false
inhibit_all_warnings

类似的,还有很多其他用ruby去实现的feature。

二、Pods目录

Pods目录是pod install之后CocoaPod生成的目录。

目录的组成部分:

  • 1、Pods.xcodeproj,Pods库的工程;每个Pod库会对应其中某个target,每个target都会打包出来一个.a文件;
  • 2、依赖库的文件目录;以SDWebImage为例,会有个SDWebImage目录存放文件;
  • 3、manifest.lock,Pods目录中的Pod库版本信息;每次pod install的时候会检查manifest.lock和Podfile.lock的版本是否一致,不一致的则会更新;
  • 4、Target Support Files、Headers、Local Podspecs目录等;Target Support Files里面是一些target的工程设置xcconifg以及脚本等,Headers里面有Public和Private的头文件目录,Local Podspecs是存放从本地Pod库install时的podspec;

三、CocoaPods的其他重要部分

1.Podfile.lock文件 pod install会解析依赖并生成Podfile.lock文件;如果Podfile.lock存在时执行pod install,则不会修改已经install的pod库。(注意,pod update则会忽视Podfile.lock进行依赖解析,最后重新install所有的Pod库,生成新的Podfile.lock) 在多人开发的项目中,Pods目录由于体积较大,往往不会放在Git仓库中,Podfile.lock文件则建议添加到Git仓库。当其他人修改Podfile时,pod install生成新的Podfile.lock文件也会同步到Git。这样能保证拉下来的版本库是其他人一致的。

实际开发中,也会通过依赖打平来避免多人协作的Pod版本不一致问题。 pod install的时候,Pods目录下生成一个Manifest.lock文件,内容与.lock文件完全一致;在每次build工程的时候,会检查这两个文件是否一致。

2、Pod库的podspec文件 在每个Pod库的仓库中,都会有一个podspec文件,描述Pod库的版本、依赖等信息。 如下,是一个普通的Pod库的podspec:

3、Pod库依赖解析 CocoaPod的依赖管理相对第三方库手动管理更加便捷。 在手动管理第三方库中,如果库A集成了库F,库B也集成了库F ,就会遇到库F符号冲突的问题,需要将库A/B和库F的代码分开,手动添加库F;后续如果库A/B版本有更新,也需要手动去处理。 而在CocoaPod依赖解析中,可以把每个Pod库都看成一个节点,Pod库的依赖是它的子节点; 依赖解析的过程,就是在一个有向图中找到一个拓扑序列。 一个合法的Podfile描述的应该是一个有向无环图,可以通过拓扑排序的方式,得到一个AOV网。 按照这个拓扑序列中的顶点次序,可以依次install所有的Pod库并且保证其依赖的库已经install。

有时候会陷入循环依赖的怪圈,就是因为在有向图中出现环,则无法通过算法得到一个拓扑排序。

四、Pods工程和主工程的关系

在实际的开发过程,容易知道Pods工程是先编译,编译完再执行主工程的编译;因为主工程的Linked Libraries里面有libPods-LearnPod.a的文件。(LearnPod是target的名字,下面的示例图都是用LearnPod作为target名)

那么Pod库中的target编译顺序是如何决定? 打开workspace,选择Pods工程。从上图分析我们知道,主工程最终需要的是libPods-LearnPod.a这一个静态库文件。 我们通常打包,最终名字都是target的名字;而静态库通常会在前面加上lib的前缀。所以libPods-LearnPod.a这个静态库的target名字应该是Pods-LearnPod。 从下图我们也可以确定,确实是在前面添加了lib的前缀。

看看Pods-LearnPod的Build Phases选项,从target依赖中可以看到其他两个target。

分析至此,我们可以知道这里的编译顺序是AFNetworking、SDWebImage、Pods-LearnPod、LeanPod(主工程target)。 接下来我们分析编译过程。AFNetworking因为没有依赖,所以编译的时候只需要知道自己的.h/.m文件。

对于Pods-LearnPod,其有两个依赖,分别是AFNetworking和SDWebImage;所以在Header Search Paths中需要设置这两个库的Public头文件地址。

编译的结果是3个.a文件(libPods-LearnPod.a、libAFNetworking.a、libSDWebImage.a),只有libPods-LearnPod.a是主工程的编译依赖。那么libPods-LearnPod.a是否为多个.a文件的集合?

从libPods-LearnPod.a的大小,我们可以知道libPods-LearnPod不是多个.a的集合,仅仅是作为主工程的一个依赖,使得Pod库工程能先于主工程编译。 那么,主工程编译的时候如何去找到AFNetworking的头文件和.a文件? 从主工程的Search Paths我们可以看到,Header是有说明具体的位置; 同时Library也有相对应的Paths,在对应的位置放着libAFNetworking.a文件;

这些信息是CocoaPod生成的一份xcconfig,里面的HEADER_SEARCH_PATHS和LIBRARY_SEARCH_PATHS会指明这两个地址。

对于资源文件,CocoaPods 提供了一个名为 Pods-resources.sh 的 bash 脚本,该脚本在每次项目编译的时候都会执行,将第三方库的各种资源文件复制到目标目录中。 CocoaPods 通过一个名为 Pods.xcconfig 的文件来在编译时设置所有的依赖和参数。 在编译之前会检查pod的版本是否发生变化(manifest和.lock文件对比),以及执行一些自定义的脚本。 Pod库的子target在指定armv7和arm64两个架构的时候,会分别编译生成armv7和arm64的.a文件;然后再进行一次合并操作,得到一个.a文件。 编译完成后进行链接,在armv7和arm64都指定时,会分别进行链接,最后合并得到可执行文件。 得到可执行文件后,会进行asset、storyboard等资源文件的处理;还会执行pod的脚本,把pod的资源复制过来。 全部准备就绪,就会生成符号表,包括.a文件里面的符号。 最后进行签名、校验,得到.app文件。

五、常用Pod指令

pod install,最常用的指令; pod update,更新repo并重新解析依赖; pod install --repo-update,类似pod update; pod install --no-repo-update,忽略Pod库更新,直接用本地repo进行install; pod update --no-repo-update,类似pod install; pod update AFNetworking,更新指定库;

以上所有指令都可以添加 --verbose ,查看更详细的信息; xcconfig在新增configuration之后,需要重新pod install,并修改xcconfig。

附录

CocoaPods使用总结 基于 CocoaPods 进行 iOS 开发 pod install vs. pod update CocoaPods 都做了什么?

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • iOS近距离实时合唱

    前言 在前文iOS近距离实时通信解决方案的基础上对MultipeerConnectivity深入研究,实现实时合唱的效果,重点介绍MultipeerConnec...

    落影
  • 使用VideoToolbox硬编码H.264

    前言 H.264是目前很流行的编码层视频压缩格式,目前项目中的协议层有rtmp与http,但是视频的编码层都是使用的H.264。 在熟悉H.264的过程中,为...

    落影
  • OpenGLES进阶教程8-obj文件和mtl文件解析

    教程 距离上一篇教程已经有两个月了,这两个月详细阅读GPUImage的源码,并写了详细解析,发现对OpenGLES的深入了解很有帮助。 上周一个简书的朋友问我...

    落影
  • 2018 AI in China之智能制造数据驱动产业变革高峰论坛在京召开

    数据猿
  • Django中使用SummerNote富文本编辑器

    这款编辑器基于Bootstrap和Jquery,也就是说项目中要先准备好Bootstrap和JQuery相关文件,当然也可以在线调用。相对于CKEditor我更...

    弄啥嘞
  • Python习题集(十四)

    https://www.cnblogs.com/poloyy/category/1676599.html

    小菠萝测试笔记
  • 【JavaWeb】106:导航栏的实现

    请求路径为:categoryServlet,其携带的methodName为queryAll。

    刘小爱
  • Python爬取杜赛博客教程内容,应用pdfkit打印pdf文件

    听说杜佬的博客更新了,尤其是django教程,本渣渣由于没有钱充值网络,所以一直是断网状态下,本身也是有搜集教程进文件夹吃灰的通病,因此就有了这样一篇渣渣文,应...

    二爷
  • SpringBoot非官方教程 | 第十二篇:springboot集成apidoc

    首先声明下,apidoc是基于注释来生成文档的,它不基于任何框架,而且支持大多数编程语言,为了springboot系列的完整性,所以标了个题。 一、apidoc...

    方志朋
  • TCGAG多组学联合分析数据库

    之前我们在介绍GEPIA的时候,说这个数据库只能用于TCGA表达数据的一些分析。但是对于TCGA数据而言,里面包括相同样本的表达、突变、拷贝数、甲基化以及临床信...

    医学数据库百科

扫码关注云+社区

领取腾讯云代金券