CocoaPods 可以说是 iOS 开发应用最广泛的包管理工具,本篇文章主要介绍 CocoaPods 的第三方库是怎样从网络集成到我们本地的项目当中,也是制作私有库、开源库和 iOS 项目组件化的一个知识铺垫。
让我们从一张图片开始:
CocoaPods 工作流程 |
---|
远程索引库
远程索引库里存放的是各种框架的描述信息,这个库托管在 Github 上,地址如下:
https://github.com/CocoaPods/Specs
每个框架下有数个版本,每个版本有一个 json
格式的描述信息,如下:
|
|
其中 git
字段表示该框架的托管地址,也就是上面时序图中的 远程框架库
。
本地索引库
在 install cocoapods
命令后,需要执行 pod setup
这个命令,pod setup
命令就是将远程索引库克隆到本地来,本地索引库的路径如下:
|
|
本地索引库和远程索引库的目录一致,结构如下:
本地索引库 |
---|
本地索引文件
当执行 pod search
命令时,如果本地索引文件不存在,会创建这个文件。
|
|
如果这个文件存在,则会在此文件中进行索引,确认所需要的框架是否存在,本地索引文件的路径如下:
|
|
制作 CocoaPods 库
上面的流程清楚以后,制作 CocoaPods 库相信应该不会太难了,大致分为以下几步:
- 托管框架源码到 Git;
- 创建框架描述信息;
- 上传框架描述信息到
https://github.com/CocoaPods/Specs
; - 命令行
pod setup
, 创建本地索引库; - 命令行
pod install
,将框架集成到项目中;
现在开始动手吧!首先在桌面新建一个 testLib
目录,在该目录下新建一个 Classes
目录,用来存放框架源码,然后将 testLib
托管到 Git。
你可以给 Classes 目录任意的命名,Classes 只是一种约定俗称的命名。
pod spec
pod spec
命令用于创建框架的描述信息文件,文档如下:
https://guides.cocoapods.org/syntax/podspec.html
现在在 testLib
目录下执行:
|
|
目录下会创建一个 testLib.podspec
文件,然后编辑这个文件,主要有以下几个字段:
- version:这个 spec 映射的版本,保证 Git 的
releases
与此对应; - homepage:项目主页;
- source:框架源代码的托管地址;
- tag:与 version 对应;
- source_files:框架源代码的目录、文件、文件类型等规则;
CocoaPods 公开库
根据上面的步骤,现在你需要将生成的 testLib.podspec
文件上传到远程索引库,在此之前,你需要注册一个 Trunk 账号,文档如下:
https://guides.cocoapods.org/making/getting-setup-with-trunk.html
现在执行下面的命令,记得修改邮箱昵称描述等:
|
|
你的邮箱会收到一封邮件,打开邮件里面的链接,会有类似 you can back termainal
的提示,现在回到终端。
|
|
检查 testLib.podspec
的合法性,根据错误提示修复问题,当显示 passed validation
后,执行下面的命令:
|
|
提示信息如下:
|
|
此时你的 testLib.podspec
就会 pull request
到远程索引库,CocoaPods 官方审核通过后,就可以出现在远程索引库中,当远程索引库收录后:
|
|
这时你的本地索引库,会新加入 testLib.podspec
这条记录,但是本地索引文件还未更新,因此删除掉以下路径的本地索引文件:
|
|
执行 pod search testLib
命令,当 search_index.json
文件重建完毕后,就可以在使用这个远程框架库了。
CocoaPods 私有库
有了公开库,当然也就有私有库,私有库主要分为远程和本地两种,什么时候会用到私用库呢?也就是需要将源码封装成库,但又不希望将源码公开,一般的使用场景是公司内部的组件化开发。
本地私有库
本地私有库就是创建一个仓库,将其存储在本地,在本地的其他工程中直接使用。首先在桌面新建一个库,路径如下:
|
|
接着创建一个壳工程,现在你的目标是使用 pod
的方式,将 NetWork
这个库集成到壳工程中。
创建本地 GIt 仓库
将 NetWork
加入到 Git,命令如下:
|
|
创建库描述文件
和公开库一样,我们需要先创建一个 spec
文件,命令如下:
|
|
编辑 NetWork.podspec
文件,修改成下面这样:
|
|
现在你的本地库已经准备完毕了,下面就可以使用这个库了。
导入本地私有库
现在进入到壳工程目录下,执行命令:
|
|
编辑 Podfile
文件,如下:
|
|
这里有一个 path
关键字,它表示在 pod install
执行时,在指定的路径下寻找 NetWork.podspec
文件。
下面执行 pod install
命令,提示信息如下:
|
|
现在 NetWork
这个库就集成到了壳工程中。
与使用远程库不同,本地库的源文件会在 Development Pods
这个目录下,而不是 Pods
目录,顺便一提,CocoaPods 的库开发,一般也是这样搭建环境的,开发完成后再修改 spec
文件,将其 pull request
到远程索引库。
CocoaPods 模板库
本地私有库这个方式还存在以下问题:
- 需要手动创建
podspec
文件; - 无法单独测试,需要依托于壳工程运行;
假设我们有一个基础组件,里面全部是扩展文件,无法单独运行,如果依托壳工程运行,只有这一个组件,那么这个壳工程实际跟测试工程是一样的,但壳工程内有多个组件呢?
我们在壳工程中进行测试的话,不但要对其他的组件进行编译,而且自己负责的组件也可能会收到其他组件的影响,这样也就失去了组件化开发的本意,那么怎么优化呢?
单独测试
首先在 LocalLib/NetWork/
路径下创建一个测试工程 Example
,然后将 Classes
拖到这个测试工程中,这里需要注意的是,Example
和 Classes
是引用关系,不要 Copy。
简单粗暴的拖拽,现在 Example
工程就可以使用 NetWork
库了。
另外一种方式是将 NetWork
通过 CocoaPods 安装在 Example
中,和安装在壳工程一样。
看到这里,是不是感觉很烦?就是想做个测试而已,还要拖来拖去,那么繁琐。
不要着急下面来介绍一种更快捷高效的方式,执行下面的命令:
|
|
现在我们就有了一个 CocoaPods 的模板工程,它的结构是这样的:
|
|
看吧,把源码拖到 ReplaceMe.swift
的同级目录,执行 pod install
,就完成了本地私有库和其测试工程。
这一步可能会有 Swift 语言版本的问题,保持测试工程和私有库源码语言版本一致就可以。
远程私有库
远程私有库工作流程 |
---|
现在使用 pod lib create
就可以方便的生成一个本地私有库了,但是本地私有库有一定的局限性,例如:
- 需要在
Podfile
文件中主动指明路径; - 版本升级不容易维护;
- 多人开发时,不方便进行合作;
远程私有库就可以方便的解决以上的问题,制作远程私有库分为以下几个步骤:
- 创建私有 Git 远程仓库;
- 创建私有 CocoaPods 远程索引库;
- 创建 Pod 所需要的项目工程文件,并上传到 Git 远程私有库;
- 验证
podspec
描述文件; - 向私有 CocoaPods 远程索引库提交
podspec
描述文件; - 使用 Pod 库;
Git 仓库的创建在此就不在赘述了,本文中我使用码市做示例,私有 CocoaPods 远程索引库实际上也是一个 Git 仓库,现在我们有两个私有库,一个用来存放 Pod 库的源码,一个用来存放 Pod 库的描述文件。
SSH 授权
添加私有索引库需要使用 SSH 授权,也是和 Git 仓库一样的,了解的同学可以跳过这一步骤,首先创建公钥:
|
|
然后找到下面的文件:
|
|
里面存放的字符就是公钥了,然后将公钥添加码市,链接如下:
|
|
添加私有远程索引库
现在执行 pod repo
,可以看到下面的信息:
|
|
现在我们只有一个 CocoaPods 远程索引库,也是官方的索引库,下面执行:
|
|
此时我们的 CocoaPods 远程索引库就安装好了,到下面的路径去看一下:
|
|
上传源码到 Git
还记得 pod lib create
命令吗?前面我们使用它来制作了本地私有库,现在它又排上用场了,执行:
|
|
源码拖到 ReplaceMe.swift
的同级目录,它现在看起来应该是这个样子:
|
|
执行 pod install
,就完成了本地私有库和其测试工程,通过测试之后,我们就可以把这个本地私有库制作成远程私有库了。
首先修改 BaseComponent.podspec
文件:
|
|
然后使用质量检查工具验证一下,保证在 BaseComponent.podspec
路径下,执行:
|
|
如果你使用 Swift,会得到一个提示:
|
|
根据提示修复就好了,在这里你可能会遇到很多 Swift 语言版本的问题,善用搜索引擎吧,通过检验以后提示如下:
|
|
下面执行:
|
|
然后和远程仓库进行关联:
|
|
上传 Spec 到远程索引库
首先执行下面的命令:
|
|
提示如下:
|
|
根据提示,我们需要先建立一个 Tag:
|
|
检验通过后,提示如下:
|
|
然后将 podspec
文件推到远程私有索引库:
|
|
现在看一下本地索引库中是否已经添加成功:
|
|
再看一看你的远程索引库中是否添加成功,现在搜索一下本地索引文件试试:
|
|
现在我们可以找到自己的远程私有库了,下面将 Podfile
文件改成这样:
|
|
执行 pod install
,整个远程私有库的搭建和使用就完成了。
CocoaPods 库升级
我们使用远程私有库的目的就是为了版本升级和多人开发,那么远程私有库如何进行升级,升级后其他人又如何使用呢?现在我们给 BaseComponent
进行升级,给它再增加一些功能:
|
|
在 BaseComponent
的测试工程中测试无误后,将 BaseComponent.podspec
的 version
修改一下:
|
|
现在检查一下私有库是否有错误:
|
|
检查通过后就可以将 BaseComponent
的 0.2.0
版本推到远程私有库中,同时建立 0.2.0
的 Tag。
然后检查一下 spec
文件:
|
|
检查通过后,执行:
|
|
远程私有库和远程私有索引库全部更新完毕,现在我们回到使用者的视角,这个库可以使用了吗?还不行。
因为本地的索引文件还没有更新,这个源还找不到,现在进入壳工程,执行:
|
|
BaseComponent
的 0.2.0
版本就乖乖的进入了壳工程。
CocoaPods 库依赖
在上面的壳工程中,我们引入了 Alamofire
这个框架,但是如果用着用着突然觉得不爽了,要换框架,这时 Alamofire
的引用在工程中已经无处不再了,这样换的话是不是很痛苦?
所以我们一般在开发中都会封装网络请求,做到分层解耦,这样如果换框架,只修改网络请求这层的封装就可以了,那么现在我们需要将 Alamofire
封装成 Network
,再把 Network
弄到我们的 BaseComponent
里面去,怎么做呢?
现在先将 Network
拖到 BaseComponent
的 Classes
目录中,因为 BaseComponent
的测试工程没有 Alamofire
,所以 Network
肯定是会报错了,不要慌,下面我们修改 spec
文件:
|
|
dependency
指明了这个库的依赖,改好之后 pod install
,Alamofire
就安装到了 BaseComponent
的测试工程中,现在就可以使用 Alamofire
进行网络请求封装,直接 import
就可以了:
|
|
现在再进行一次远程私有库升级,整个依赖就做好了,需要注意的是,已经做了依赖的话,相关的库就可以从 Podfile
文件中去掉了:
|
|
现在是我们依赖的是公开库,直接升级 CocoaPods 私有库就可以,但是如果依赖的是另外一个私有库,这个依赖关系最终还要上传到私有索引库中,这样其他人在使用的时候才会知道这个依赖关系,现在走一下升级的流程,你会得到类似这个报错:
|
|
这个报错是因为 TargetComponent
这个库没有在官方的索引库当中,忽略就可以了,当然,在使用的时候,TargetComponent
这个库可以在你的本地索引文件中找到,否则无法使用。
CocoaPods 资源依赖
现在我们可以让一个库依赖另外一个库,但是看下面这段代码:
|
|
这段代码读取了一个 XIB 文件,这个库的结构是这样的:
|
|
我们可以成功调用这个方法吗?不能,因为 TZYTabBarMiddleView.xib
这个文件的 Target 是 MainModule
,使用 CocoaPods 把这个库安装到我们项目后,XIB 文件即使在,也是在 Pods 这个工程里,而我们在壳工程中使用 TZYTabBarMiddleView.xib
,也是必然找不到的。
下面我们把模板库的测试工程编译一下,打开 Products 目录下的 .app
文件,看一下文件结构:
|
|
通过路径可以看到,TZYTabBarMiddleView.nib
是在:
|
|
这个路径下面,因此 mainBundle.loadXIb
肯定是找不到资源文件的,那么该如何修改呢?
|
|
这部分的重点就是 Bundle(for aClass: Swift.AnyClass)
这个方法。
CocoaPods 图片依赖
上面我们讲到了怎样使用 Pod 库里面的 XIB 文件,但是还有其他资源文件,例如图片、音频、视频,图片我们一般是放在 Assets.xcassets
,但是 Pod 库并没有对应的路径,那么它所需要的图片放在哪里,已经如何使用呢?现在使用 pod lib create
命令创建一个 Pod 库,进入以下路径:
|
|
把一些图片拖入到 Assets
文件夹内,然后在 podspec
文件中加入以下代码:
|
|
然后执行 pod install
,Pod 库中就出现了之前拖入 Assets
文件夹的图片,但是现在还不能使用,我们先来看一下打包以后这些图片的路径:
|
|
可以看到,打包后的路径在:
|
|
这个路径下面,而代码中的 UIImage(named: "tabbar_bg")
读取的是 mainBundle
下的资源文件,因此还是找不到的,那么这时使用图片,应该将代码改成这样:
|
|
这里需要注意的是,文件名需要完整。以上是在代码中加载图片,如果是在 XIB 中加载图片,应该怎样做呢?那么再看一下上面的目录结构,TZYTabBarMiddleView.nib
和 TargetComponent.bundle
处于同一个目录,我们可以在 TZYTabBarMiddleView.xib
中通过相对路径,使用 TargetComponent.bundle
里面的图片,因此在 XIB 中,图片名应该是这样的:
|
|
CocoaPods 子库
现在我们实现了一个完整的远程私有库,可以升级,依赖其他的库,提供给其他人使用,但是现在还有一点问题,其他人如果要用我们的库,就需要把 BaseComponent
完整的克隆过来,但是他可能只需要 BaseComponent
里面的 Network
,其他的扩展、工具等并不想使用,也不想导入过来,怎么办?有两种方案:
- 把
Network
剥离出来,再单独建一个远程私有库; - 使用子库迁出
Network
;
第一种方案大家已经知道了,就是上面的一大篇,麻烦不说,而且东西一多起来,这里一个库,那里一个库,也不容易管理,所以,下面就有请子库隆重登场。
在开始之前,我们先来开一个东西,下面是 pod search AFN
中的一条记录:
|
|
注意 Subspecs
这里,它就是本节要讲的东西,首先将 spec
改成下面这样:
|
|
在这里要注意 source_files
和 dependency
以及版本的变化,修改完成推到远程索引库,并打好 0.4.0
的分支,执行:
|
|
现在就可以找到了:
|
|
那么如何使用呢?把 Podfile
改成这样:
|
|
现在 pod install
,就完成了子库的创建和使用。
结尾
这篇文章断断续续写了快一周,其实一般我们用不到 CocoaPods 这些功能,不过了解一下 CocoaPods 的工作原理也是没有坏处的。
这篇文章主要是为了使用 CocoaPods 进行组件化开发,关于组件化开发的思想,可以看下面这篇文章: