CocoaPods 知识
- 目录
- 前言
- CocoaPods安装
- CocoaPods原理
- CocoaPods使用
1、 前言
CocoaPods是OS X和iOS下的一个第三类库管理工具,通过CocoaPods工具我们可以为项目添加被称为“Pods”的依赖库(这些类库必须是CocoaPods本身所支持的),并且可以轻松管理其版本。
相关资料
- CocoaPods官网
- CocoaPods原理
- CocoaPods源码
2、 CocoaPods安装
1、设置 ruby 源
Mac 系统自带的会安装好 ruby 环境
1.1、查看自己电脑的 ruby 源
- ruby -v
ruby -v
- 如果自己电脑版本低于这个版本就升级 ruby ,上面显示我的电脑版本不需要升级,可以忽略下面的升级操作
sudo gem update --system
- 要是没有ruby环境, 执行下面的指令
gem install ruby
1.2、更换 ruby 镜像
- ruby 默认的原地址是国外网络地址,通过下面命令查看当前的镜像
gem sources -l
*** CURRENT SOURCES ***
https://rubygems.org/
- 移除当前镜像
gem sources --remove https://rubygems.org/
https://rubygems.org/ removed from sources
- 添加国内的 ruby 镜像
gem sources -a https://gems.ruby-china.com/
https://gems.ruby-china.com/ added to sources
- 再次查看当前镜像,发现已经替换成功
gem sources -l
*** CURRENT SOURCES ***
https://gems.ruby-china.com/
2、安装 CocoaPods
ruby 环境安装后,就可以安装 CocoaPods 了
2.1 检查pod版本
pod --version
2.2 卸载CocoaPods
#卸载
sudo gem uninstall cocoapods
#卸载指定版本
sudo gem uninstall cocoapods -v 1.9.3
2.3 安装
方法一
#下载最新版本
sudo gem install cocoapods
#下载指定版本
sudo gem install cocoapods -v 1.9.3
等待了几分钟后,显示下面的信息,便表示已经安装成功了。
方法二
sudo gem install -n /usr/local/bin cocoapods
2.2 检测是否安装成功
- 可以通过检查pod版本指令查看是否安装成功
pod --version
2.3 下载文件
pod setup
2.4 验证安装成功与否
pod search AFNetworking
3、 CocoaPods原理
核心组件
CocoaPods 是一个 objc 的依赖管理工具,而其本身是利用 ruby 的依赖管理 gem 进行构建的。
CocoaPods是用 Ruby 写的,并由若干个 Ruby 包 (gems) 构成的。在解析整合过程中,最重要的几个 gems 分别是:
- CocoaPods/Specs
- CocoaPods/CocoaPods
- CocoaPods/Core
- CocoaPods/Xcodeproj
CocoaPods/Specs
这个是一个保存第三方组件 podspec 文件的仓库。第三方组件开发完成之后,会传一份 podspec 文件传到 CocoaPods,这个 Specs 包含了每个第三方组件所有版本的 podspec 文件。当使用某个第三方组件时,如果这些组件支持 CocoaPods,会在 Podfile 中指定 source,例如下面这样:
source 'https://github.com/CocoaPods/Specs.git'
当执行 pod install 或 pod update 等一些命令时,便会从这个仓库找到组件指定版本的 podspec 文件,然后根据这个 podspec 配置信息去获取组件。
CocoaPods/CocoaPod
这是是一个面向用户的组件,每当执行一个 pod 命令时,这个组件都将被激活。该组件包括了所有使用 CocoaPods 涉及到的功能,并且还能通过调用所有其它的 gems 来执行任务。
CocoaPods/Core Core
组件提供支持与 CocoaPods 相关文件的处理,文件主要是 Podfile 和 podspecs。
当执行 pod install等一些命令时。Core组件会解析第三方组件开发者上传的podspec文件和使用者的podfile,以此确定需要为project引入哪些文件。除此之外,当执行与这些文件一些相关的命令时,也由这部分组件处理,例如使用 pod spec lint 来检测 podspec 文件的有效性。
CocoaPods/Xcodeproj
这个 gem 组件负责所有工程文件的整合。它能够对创建并修改 .xcodeproj 和 .xcworkspace 文件。它也可以作为单独的一个 gem 包使用。如果你想要写一个脚本来方便的修改工程文件,那么可以使用这个 gem。
Podfile
Podfile 是一个文件,用于定义项目所需要使用的第三方库。该文件支持高度定制,你可以根据个人喜好对其做出定制。
Podspec
.podspec 也是一个文件,该文件描述了一个库是怎样被添加到工程中的。它支持的功能有:列出源文件、framework、编译选项和某个库所需要的依赖等。
Ruby 概述
方法
- 简单的方法
Ruby 代码在调用方法时可以省略括号。
def method_name (var1=value1, var2=value2)
expr..
end
ruby中的方法以'def'开头,以'end'作为结尾,我们可以为参数设置默认值,如果方法调用时未传递必需的参数则使用默认值,上例中的value1和value2就是默认值。
- 可变数量的参数
def sample (*test)
puts "参数个数为 #{test.length}"
for i in 0...test.length
puts "参数值为 #{test[I]}"
end
end
sample "Zara", "6", "F"。
数据类型--Hash
哈希(Hash)是类似 "key" => "value" 这样的键值对集合。哈希类似于一个数组,只不过它的索引(或者叫"键")不局限于使用数字,Hash 的索引几乎可以是任何对象。
Hash 虽然和数组类似,但却有一个很重要的区别:Hash 的元素没有特定的顺序。 如果顺序很重要的话就要使用数组了。
pod 'SwViewCapture', :git=>'[email protected]:startry/SwViewCapture.git', :branch=>'master'
def pod(name = nil, *requirements)
unless name
raise StandardError, 'A dependency requires a name.'
end
current_target_definition.store_pod(name, *requirements)
end
pod方法后面跟着的参数就是一个Hash的对象,写成key-value的形式就是
{
":git": "[email protected]:startry/SwViewCapture.git",
":branch": "'master'"
}
block
Ruby中do ~end之间的部分称为块,也可以写为{..}
所以这个target方法可以以这种形式调用:
target('PodSample') {
pod('SDWebImage', '~> 4.4.2')
}
也可以使用我们常见的形式调用:
target('PodSample') do
pod('SDWebImage', '~> 4.4.2')
end
eval
这个方法会将字符串当做代码来执行,也就是说 eval 模糊了代码与数据之间的边界,iOS开发过程中也会使用eval执行js代码。
eval "1 + 2 * 3" => 7
Podfile&Podfile.lock的解析
Podfile
CocoaPods内部定义了一些配置方法,把方法参数转化为内部Hash变量的属性。
Podfile.lock
Podfile.lock文件是用数据描述语言YAML编写的,YAML(YAML Ain’t Markup)是一种简洁的非标记语言,以数据为中心,使用空白,缩进,分行组织数据,从而使得表示更加简洁易读,其可以与json互转,CocoaPods内部是把Podfile.lock文件解析成Hash类型,从而进行参数数据查询和与Podfile文件中的参数进行对比。
4、CocoaPods使用
- 远程 pods 库:
- 可以是CocoaPods 公共库,也可以是一个自定义的 Git 仓库(远程私有库)
- 本地索引库:
- 位置可以通过命令$cd ~/.cocoapods/repos进入.公共库和私有库都会在该路径下
- 源代码库:
- 可以是CocoaPods公共Git仓库中的库,也可以用任何一个Git, Mercurial或者SVN仓库取代,并且还可以指定具体的commit, branch或者tag。
基础
1. 创建Podfile文件
#进入项目根路径中执行,生成Podfile文件(如果有Podfile文件不用执行pod init)
pod init
说明:Podfile文件详细描述了一个或多个工程中targets的依赖关系
2. Podfile添加第三方库依赖
target 'QSAppDemo' do
pod 'AFNetworking'
pod 'YYModel', '~> 1.0.4'
end
3. 下载和安装第三方库
pod install
- 下载成功后,使用CocoaPods 生成的 .xcworkspace 文件来打开工程;每次更改了 Podfile 文件,要重新执行一次pod update命令;
- 发生执行pod install或pod update都卡在Analyzing dependencies的情况,是因为要升级CocoaPods的spec仓库,命令后添加--verbose --no-repo-update 参数可以省略此步。
pod指定依赖项版本范围
- 如果依赖项后不指定版本,默认取最新版本
pod 'AFNetworking'
版本控制
> 0.1 高于0.1版本(不包含0.1版本)的任意一个版本
>= 0.1 高于0.1版本(包含0.1版本)的任意一个版本
< 0.1 低于0.1版本(不包含0.1版本)的任意一个
<= 0.1低于0.1版本(包含0.1版本)的任意一个
~> 0.1.2 版本 0.1.2的版本到0.2 ,不包括0.2。这个基于你指定的版本号的最后一个部分。这个例子等效于>= 0.1.2并且 <0.2.0,并且始终是你指定范围内的最新版本。
pod制定依赖库的分支或节点
- 引入master分支(默认)
pod 'AFNetworking', :git => 'https://github.com/AFNetworking/AFNetworking.git'
- 引入指定的分支
pod 'AFNetworking', :git => 'https://github.com/AFNetworking/AFNetworking.git', :branch => 'develop'
- 引入某个节点的代码
pod 'AFNetworking', :git => 'https://github.com/AFNetworking/AFNetworking.git', :tag => '2.7.0'
- 引入某个特殊的提交节点
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :commit => '685e31a31bb1ebce3fdb5a752e392dfd8263e169'
- 使用本地文件
我们也可以指定依赖库的来源地址。如果我们想引入我们本地的一个库,可以这样写:
pod 'AFNetworking', :path => '~/Documents/AFNetworking'
关于Podfile中一些配置说明
- Podfile文件用法详解
Source:
指定pod的来源。如果不指定source,默认是使用CocoaPods官方的source
# 使用官方默认地址(默认)
source 'https://github.com/CocoaPods/Specs.git'
# 公司私有库
source '私有库url'
Target configuration (目标项配置)
platform用于指定应建立的静态库的平台。CocoaPods提供了默认的平台版本配置:
#指定具体平台和版本
platform :ios, '4.0'
platform :iOS
use_frameworks!:
使用此命令会在Pods工程下的Frameworks目录下生成依赖库的framework,如果不使用,会在Pods工程下的Products目录下生成.a的静态库。
target 'Demo' do
use_frameworks!
end
Dependencies(依赖项)
Podfile指定每个target的依赖项
pod指定特定的依赖库
podspec可以提供一个API来创建podspecs
target通过target指定依赖范围
target
在给定的块内定义pod的target(Xcode工程中的target)和指定依赖的范围。一个target应该与Xcode工程的target有关联。默认情况下,target会包含定义在块外的依赖,除非指定不使用inherit!来继承(说的是嵌套的块里的继承问题)
定义一个Apptarget仅引入AFNetworking库,定义AppTeststarget 引入Nimble的同时也会继承Apptarget里面的AFNetworking库
target 'App' do
pod 'AFNetworking'
target 'AppTests' do
inherit! :search_paths
pod 'Nimble'
end
end
- target块中嵌套多个子块
target 'ShowsApp' do
# ShowsApp 仅仅引入ShowsKit
pod 'ShowsKit'
# 引入 ShowsKit 和 ShowTVAuth
target 'ShowsTV' do
pod 'ShowTVAuth'
end
# 引入了Specta和Expecta以及ShowsKit
target 'ShowsTests' do
inherit! :search_paths
pod 'Specta'
pod 'Expecta'
end
end
- 抽象target
定义一个新的抽象目标,它可以方便的用于目标依赖继承。
简单写法
abstract_target 'Networking' do
pod 'AlamoFire'
target 'Networking App 1'
target 'Networking App 2'
end
定义一种abstract_target包含多个target
# 注意:这是个抽象的target也就是说在工程中并没有这个target引入ShowsKit
abstract_target 'Shows' do
pod 'ShowsKit'
# ShowsiOS target会引入ShowWebAuth库以及继承自Shows的ShowsKit库
target 'ShowsiOS' do
pod 'ShowWebAuth'
end
# ShowsTV target会引入ShowTVAuth库以及继承自Shows的ShowsKit库
target 'ShowsTV' do
pod 'ShowTVAuth'
end
# ShowsTests target引入了Specta和Expecta库,并且指明继承Shows,所以也会引入ShowsKit
target 'ShowsTests' do
inherit! :search_paths
pod 'Specta'
pod 'Expecta'
end
end
Build configurations(编译配置)
默认情况下, 依赖项会被安装在所有target的build configuration中。为了调试或者处于其他原因,依赖项只能在给定的build configuration中被启用。
下面写法指明只有在Debug和Beta模式下才有启用配置
pod 'MJRefresh', :configurations => ['Debug', 'Beta']
或者,可以弄白名单只指定一个build configurations。
pod 'MJRefresh', :configuration => 'Debug'
注意:默认情况下如果不指定具体生成配置,那么会包含在所有的配置中,如果你想具体指定就必须手动指明。
Subspecs
一般情况我们会通过依赖库的名称来引入,cocoapods会默认安装依赖库的所有内容。
我们也可以指定安装具体依赖库的某个子模块,例如:
# 仅安装QueryKit库下的Attribute模块
pod 'QueryKit/Attribute'
# 仅安装QueryKit下的Attribute和QuerySet模块
pod 'QueryKit', :subspecs => ['Attribute', 'QuerySet']
def
我们还可以通过def命令来声明一个pod集:
def 'CustomPods'
pod 'IQKeyboardManagerSwift'
end
然后,我们就可以在需要引入的target处引入:
target 'MyTarget' do
CustomPods
end
这么写的好处是:如果有多个target,而不同target之间并不全包含,那么可以通过这种方式来分开引入。
post_install
当我们安装完成,但是生成的工程还没有写入磁盘之时,我们可以指定要执行的操作。
比如,我们可以在写入磁盘之前,修改一些工程的配置:
post_install do |installer| installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['GCC_ENABLE_OBJC_GC'] = 'supported'
end
end
end
pre_install
当我们下载完成,但是还没有安装之时,可以使用hook机制通过pre_install指定要做更改,更改完之后进入安装阶段。
pre_install do |installer|
# 做一些安装之前的更改
end
abstract! 和 inherit!
abstract! 指示当前的target是抽象的,因此不会直接链接Xcode target。
inherit! 设置当前target的继承模式。例如:
target 'App' do
target 'AppTests' do
inherit! :search_paths
end
end
inhibit_all_warnings!
inhibit_all_warnings! 屏蔽所有来自于cocoapods依赖库的警告。你可以全局定义,也能在子target里面定义,也可以指定某一个库:
# 隐藏SSZipArchive的警告而不隐藏ShowTVAuth的警告
pod 'SSZipArchive', :inhibit_warnings => true
pod 'ShowTVAuth', :inhibit_warnings => false
5、CocoaPods创建私有库
- 参考资料: CocoaPods创建私有库
CocoaPods拉取开源库的原理:
CocoaPods 有一个开源的索引仓库Specs,仓库存放着所有开源库的各个版本的.podspec文件,.podspec文件包含中记录着源码的地址。首次使用CocoaPods时,会将这个文件库克隆到本地~/.cocoapods/repos/master。
- 在Podfile目录下执行 pod install 命令,会从本地的索引库查找该库的.podsepc,如果本地不存在会从远程拉取最新的索引库。
- 根据索引库中查到的.podspec文件内容,获取源码地址。
- 从源码地址拉取对应版本的代码。
使用是可以发现,首次导入一个开源库时速度较慢,之后再导入时会很快。是因为CocoaPods在本地会有一个缓存目录,存放开源库的源码,首次下载后,再次导入该库时,会直接从本地复制过去。
查看缓存列表使用pod cache list,缓存路径为~/Library/Caches/CocoaPods/Pods/。
创建私有库步骤:
1. 创建podspec文件
1.1 什么是podspec?文件夹打开~/.cocoapods/repos看到
specs存放的就是cocoapod官网库的specification:说明书,通过这个podspec文件里的信息,找到对应资源URL,然后clone到我们的pod中。可以理解为书的目录,我们查找第三方库的时候实际就是查找这个specs集合。所以我们创建私有库第一步就是创建我们的spec,目录。
先创建空的repository,为了区分命名最好以spec为后缀,说明这是存说明书的库
然后将这个库添加到~/.cocoapods/repos中,操作很简单,终端执行pod命令pod repo add hxkSpec [email protected]:xiaoyiqiu/spec.git
1.2 开始创建私有库podspec,理解为pod私有库说明书
在github上创建一个存放specification的仓库,注意不是存放源码的库,一定不要搞错了
我建议先创建空的repository,为了区分命名最好以spec为后缀,说明这是存说明书的库
然后将这个库添加到~/.cocoapods/repos中,操作很简单,终端执行pod命令pod repo add TDNIMKitSpec [email protected]:strivever/TDNIMKitSpec.git
命令格式:
pod repo add 【specName】 【spec远程仓库地址】
2.制作我们的pod库
2.1 创建库
pod lib create 【你的pod库名】
2.2 配置.Podspec文件信息
Podspec文件语法
Pod::Spec.new do |s|
#pod私有库名称
s.name = 'TDNIMKit'
#pod私有库版本号
s.version = '0.1.0'
#pod私有库概要
s.summary = 'A short description of TDNIMKit.'
# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
# * Try to keep it short, snappy and to the point.
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = <<-DESC
TODO: Add long description of the pod here.
DESC
#主要,最好能访问
s.homepage = 'https://github.com/[email protected]/TDNIMKit'
# s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
#开源协议
s.license = { :type => 'MIT', :file => 'LICENSE' }
#开源作者
s.author = 'Striver'
#源码地址,clone时候就需要使用这个地址跟版本拉取
s.source = { :git => 'https://github.com/[email protected]/TDNIMKit.git', :tag =>'0.1.0' }
#支持的系统版本
s.ios.deployment_target = '8.0'
#源码相对路径
s.source_files = 'TDNIMKit/Classes/**/*'
# s.resource_bundles = {
# 'TDNIMKit' => ['TDNIMKit/Assets/*.png']
# }
# s.public_header_files = 'Pod/Classes/**/*.h'
#需要使用的框架
# s.frameworks = 'UIKit', 'MapKit'
#依赖的其它第三方库
# s.dependency 'AFNetworking', '~> 2.3'
end
- cd到源码的文件夹中:
pod lib lint [email protected]:xiaoyiqiu/spec.git,https://github.com/CocoaPods/Specs.git --allow-warnings
pod repo push spec huang.podspec [email protected]:xiaoyiqiu/spec.git,https://github.com/CocoaPods/Specs.git --allow-warnings
2.3 验证库有没问题
进行本地验证podspec文件是否正了
cd 到xxx.podspec目录:执行以下指令
pod lib lint --use-libraries --allow-warnings
2.4 编写代码
2.5 上传到gitLab托管平台
- 上传到远程服务器
- 一定要打上tag值. 需要跟podspec文件中指定的tag一致
- 将podsepec中的 source填入仓库地址 上传到仓库记得看一下远程仓库资源是否被同步上去了,不然一会校验会出现资源匹配不到。
2.6 远程仓库验证
- 方法一(推荐):
pod lib lint --sources=【gitLab ssh地址】,https://github.com/CocoaPods/Specs.git --allow-warnings
pod lib lint [email protected]:xiaoyiqiu/spec.git(远程库的地址),https://github.com/CocoaPods/Specs.git --allow-warnings
- 方法二:
pod spec lint --use-libraries --allow-warnings
验证可能很漫长,可以增加 --verbose查看日志
2.6 发布私有库
执行以下发布指令:
- 方法一:
// pod 命令:
pod repo push spec huang.podspec 【本地spec文件夹名称】【需要发布的.podspec文件 --sources=【gitLab ssh地址】,https://github.com/CocoaPods/Specs.git --allow-warnings
pod repo push spec huang.podspec [email protected]:xiaoyiqiu/spec.git,https://github.com/CocoaPods/Specs.git --allow-warnings
- 方法二:
pod命令 pod repo push 【本地spec文件夹名称】【需要发布的.podspec文件】--use-libraries --allow-warnings --verbose
- 发布成功后查看一下本地和远程应该都有了podspec
2.7 验证私有仓库是否可用
- 用pod命令进行搜索,看能否搜索到:$ pod search [私有库名字]
- 如果搜索不到,在终端执行如下命令 pod repo update然后重新search
2.8 使用私有库
6、常用pod指令
pod setup原理
本质就是将 https://github.com/CocoaPods/Specs 上的项目克隆到/Users/用户名/.cocoapods/repos目录下,若此目录下已经有这个项目,使用pod setup命令则会将项目更新到最新的状态。
pod instal和pod update的区别
执行pod install时,如果Podfile.lock文件存在, 则下载Podfile.lock文件中指定的版本安装,对于不在Podfile.lock文件中的pod库,pod install命令会搜索这个pod库在Podfile文件中指定的版本来安装;
当你想要更新pod库的版本时才使用pod update;它不管Podfile.lock是否存在, 都会读取Podfile文件的的框架信息去下载安装,下载好之后, 再根据下载好的框架信息, 生成Podfile.lock文件
//生成Podfile文件,编写需要的第三方文件
$ pod init
//安装第三方库,安装成功会生成`podfile.lock`文件用来记录第三方库版本,
后面接上--no--repo--install 的意思是不更新本地索引库
$ pod install
$ pod install --no--repo--install
//更新第三方库为本地索引库最新版本,后面接上--no--repo--update的意思是不更新本地索引库
$ pod update
$ pod update --no--repo--update
//搜索当前本地索引仓库中对应的第三方库
$ pod search 第三方库名称
//查看当前版本
$pod --version
//更新本地所有索引库 ,更新指定索引库接上索引库名称即可
$ pod repo update
//通过pod查看已添加的 repo
$ pod repo list
清除相关命令
#查看本地pod缓存
pod cache list
#清除某个库缓存
pod cache clean xxxx
# 清除所有pod缓存
pod cache clean -all
#删除缓存方法
rm ~/Library/Caches/Cocoapods/Pods/Pods/Release
其他
# 删除 search_index.json 文件
rm ~/Library/Caches/CocoaPods/search_index.json