文章目录
简书的目录跳转还在研究中...
- 什么是CocoaPods?
- CocoaPods的核心组件
- podspec文件?
- podspec是如何下载资源文件?
- 如何创建podspec文件?
- podspec如何编辑?
- 如何做文件夹层级?
- 如何关联资源文件?
- 编写swift版本库注意事项
- podspec准备就绪,如何发布出去呢?
- 发布公有库
- 发布私有库
- 发布完成去使用
- 发布完搜索不到怎么办?
- 搜索到没法下载如何是好?
- 常见发布问题
什么是CocoaPods?
CocoaPods 是开发 OS X 和 iOS 应用程序的一个第三方库的依赖管理工具。利用 CocoaPods,可以定义自己的依赖关系 (称作pods),并且随着时间的变化,以及在整个开发环境中对第三方库的版本管理非常方便。
CocoaPods 背后的理念主要体现在两个方面。首先,在工程中引入第三方代码会涉及到许多内容。针对 Objective-C 初级开发者来说,工程文件的配置会让人很沮丧。在配置 build phases 和 linker flags 过程中,会引起许多人为因素的错误。CocoaPods 简化了这一切,它能够自动配置编译选项。
其次,通过 CocoaPods,可以很方便的查找到新的第三方库。当然,这并不是说你可以简单的将别人提供的库拿来拼凑成一个应用程序。它的真正作用是让你能够找到真正好用的库,以此来缩短我们的开发周期和提升软件的质量。
CocoaPods是用 Ruby 写的,并由若干个 Ruby 包 (gems) 构成的。在解析整合过程中,最重要的几个 gems 分别是:CocoaPods/CocoaPods,CocoaPods/Core, 和CocoaPods/Xcodeproj(是的,CocoaPods 是一个依赖管理工具 -- 利用依赖管理进行构建的!)。
编者注CocoaPods 是一个 objc 的依赖管理工具,而其本身是利用 ruby 的依赖管理 gem 进行构建的。
CocoaPods的核心组件
组件 | 说明 |
---|---|
CocoaPods/CocoaPod | 这是是一个面向用户的组件,每当执行一个pod命令时,这个组件都将被激活。该组件包括了所有使用 CocoaPods 涉及到的功能,并且还能通过调用所有其它的 gems 来执行任务 |
CocoaPods/Core | Core 组件提供支持与 CocoaPods 相关文件的处理,文件主要是 Podfile 和 podspecs |
Podfile | Podfile 是一个文件,用于定义项目所需要使用的第三方库。该文件支持高度定制,你可以根据个人喜好对其做出定制。更多相关信息,请查阅Podfile 指南 |
CocoaPods/Xcodeproj | 这个 gem 组件负责所有工程文件的整合。它能够对创建并修改.xcodeproj和.xcworkspace文件。它也可以作为单独的一个 gem 包使用。如果你想要写一个脚本来方便的修改工程文件,那么可以使用这个 gem |
Manifest.lock | 这是每次运行pod install命令时创建的Podfile.lock文件的副本。如果你遇见过这样的错误沙盒文件与 Podfile.lock 文件不同步 (The sandbox is not in sync with the Podfile.lock),这是因为 Manifest.lock 文件和Podfile.lock文件不一致所引起。由于Pods所在的目录并不总在版本控制之下,这样可以保证开发者运行 app 之前都能更新他们的 pods,否则 app 可能会 crash,或者在一些不太明显的地方编译失败 |
xcproj | 如果你已经依照我们的建议在系统上安装了xcproj,它会对Pods.xcodeproj文件执行一下touch以将其转换成为旧的 ASCII plist 格式的文件。为什么要这么做呢?虽然在很久以前就不被其它软件支持了,但是 Xcode 仍然依赖于这种格式。如果没有 xcproj,你的Pods.xcodeproj文件将会以 XML 格式的 plist 文件存储,当你用 Xcode 打开它时,它会被改写,并造成大量的文件改动 |
Podfile.lock | 这是 CocoaPods 创建的最重要的文件之一。它记录了需要被安装的 pod 的每个已安装的版本。如果你想知道已安装的 pod 是哪个版本,可以查看这个文件。推荐将 Podfile.lock 文件加入到版本控制中,这有助于整个团队的一致性 |
Podspec | .podspec也是一个文件,该文件描述了一个库是怎样被添加到工程中的。它支持的功能有:列出源文件、framework、编译选项和某个库所需要的依赖等 |
关于podfile指定版本的说明
版本 | 说明 |
---|---|
pod ‘Alamofire’ | 不指定依赖库版本,表示每次都获取最新版本 |
pod ‘Alamofire’, ‘2.0’ | 只使用2.0版本 |
pod ‘Alamofire’, ‘> 2.0’ | 使用高于2.0的版本 |
pod ‘Alamofire’, ‘>= 2.0’ | 使用大于或等于2.0的版本 |
pod ‘Alamofire’, ‘< 2.0’ | 使用小于2.0的版本 |
pod ‘Alamofire’, ‘<= 2.0’ | 使用小于或等于2.0的版本 |
pod ‘Alamofire’, ‘~> 0.1.2’ | 使用大于等于0.1.2但小于0.2的版本 |
pod ‘Alamofire’, ‘~>0.1’ | 使用大于等于0.1但小于1.0的版本 |
pod ‘Alamofire’, ‘~>0’ | 高于0的版本,等同于表示每次都获取最新版本 |
podspec文件
一. 什么是podspec文件?
- podspec中spec的全称是“Specification”,说明书的意思。顾名思义,这是用来描述这个库说明信息的文件。
- podspec是cocoaPods的一种文件格式,有一套自己的语法,我们可以到cocoaPods官网进行详细了解。
- podspec描述了一个pod库的版本。它包括有关应从何处获取源、使用什么文件、应用的构建设置以及其他一般元数据(如其名称、版本和描述)的详细信息。
1. cocoapods是如何通过podspec下载资源文件?
podspec 管理几个重要信息
文件源所在git地址
,源文件所在git地址的文件路径
,源文件对应的tag值
通过以上三个内容,就精准的掌握了资源文件
然后通过下面的命令即可下载想要的资源。
pod install
当我们新建一个Podfile文件运行后,会自动生成一个Podfile.lock文件,Podfile.lock文件里存储着我们已经安装的依赖库(pods)的版本。
当我们第一次运行Podfile时,如果对依赖库不指定版本的话,cocoapods会安装最新的版本,同时将pods的版本记录在Podfile.lock文件中。这个文件会保持对每个pod已安装版本的跟踪,并且锁定这些版本。
再执行pod install的话,只会处理没有记录在Podfile.lock中的依赖库,会查找匹配Podfile中描述的版本。对于已经记录在Podfile.lock的依赖库,会下载Podfile.lock文件中记录的版本,而不会检查是否有更新。当然,如果你约束了pods的版本的话,会按照你指定的版本进行安装,同时也会更新Podfile.lock记录的信息。
简单的说:使用pod install在你的工程里安装新的pods。尽管你已经有了一个Podfile并且之前运行过pod install;尽管你只是在已经使用了CocoaPods的工程中添加/移除了pod,你都要使用pod instalpod outdated
检查记录在Podfile.lock文件中的pod版本更新情况。
当你运行pod outdated命令,CocoaPods会列出所有有新版本的pods,新版本是指比记录在Podfile.lock文件中的版本(即当前每个pod安装的版本)更新的版本。这意味着如果你对这些pod运行pod update PODNAME,它们将会更新。pod update
推荐用法:pod update + podName
当你运行pod update podName命令,CocoaPods将会尝试找到PODNAME指定pod的更新版本,而不会顾及Podfile.lock文件中记录的版本。它将会更新pod的最新可用版本.如果你运行pod update而不带pod名称,CocoaPods将会更新Podfile文件中记录的每一个pod到最新可用版本.
简单的说:只有在你想要更新pods到新的版本时才使用pod update podName
更新缓慢 ?
最近使用CocoaPods来添加第三方类库,无论是执行pod install
还是pod update
都卡在了Analyzing dependencies
不动. 原因在于当执行以上两个命令的时候会升级CocoaPods的spec仓库,加一个参数可以省略这一步,然后速度就会提升不少。加参数的命令如下:
pod install --verbose --no-repo-update
pod update --verbose --no-repo-update
但这样处理,我额外发现了一个弊端:
就是当你搜索一个库时,往往搜出来不是最新的版本.请自行更新。
--no-repo-update
不更新本地的仓库,直接更新源。
--verbose
输出详细日志信息明明线上有这个库,但是
pod search podName
却搜索不到?
open ~/Library/Caches/CocoaPods
删除该目录下的search_index.json
文件。
本地会保存一个repo镜像,search操作只是为了方便会到本地去检索,对应的应该会有个策略,看起来应该就是缓存里这个plist了,以后如果repos更新了,plist里面没有更新,那么就会有问题了。
2. 如何创建podspec文件?
说一个最简单最实用的方法 通过pod lib create + 名字
来创建
代码和资源在创建的项目中的pods -> Development Pods中编写。
说明1: 用该方法创建的项目,默认遵守了MIT License协议
说明2: 注意层级,podfile文件在Example文件夹下,podspec文件在项目根目录下
3. podspec如何编辑?
podspec文件关键字说明
# 基本信息的配置
name:框架名
version:当前版本(注意,是当前版本,假如你后续更新了新版本,需要修改此处)
summary:简要描述,在pod search的时候会显示该信息。
description:详细描述
homepage:页面链接
license:开源协议
author:作者
platform:支持最低ios版本
swift_version : swift对应的版本
# 源文件的配置
source:源码git地址
source_files:源文件(可以包含.h和.m)
subspec:子库
public_header_files:头文件(.h文件)
resource_bundles:资源文件(配置的文件会放到你自己指定的bundle中)
# 依赖的配置
frameworks:依赖的系统框架
vendored_frameworks:依赖的非系统框架
libraries:依赖的系统库
vendored_libraries:依赖的非系统的静态库
dependency:依赖的三方库
示例说明
Pod::Spec.new do |s|
s.name = 'PodspecDemo' #库的名字
s.version = '0.0.1' #库的版本号
s.summary = 'short description' # 库的简短描述信息
s.homepage = 'https://gitee.com/modularComponents/Tools' #主页地址
s.license = { :type => 'MIT', :file => 'LICENSE' } #协议
s.author = { 'Mccc' => '562863544@qq.com' } #作者信息
s.platform = :ios, '8.0' #平台
s.ios.deployment_target = '8.0' #最低支持的target
s.swift_version = '4.0' #支持的swift版本
s.description = 'long description' #库的详细描述信息
s.source = { :git => 'https://gitee.com/PodspecDemo.git', :tag => s.version.to_s } #资源的git地址和版本号
s.source_files = 'PodspecDemo/Classes/**/*' # git地址下资源文件的路径
# =======以下为可选 ===========
# 依赖
s.dependency 'SnapKit' #此库需要依赖SnapKit
# 加载资源文件
s.ios.resource_bundle = { 'ToolsModuleBundle' => 'ToolsModule/Assets/Home/**/*.{png,jpg}' } #添加资源文件
# 设置文件夹分层
s.subspec 'compass' do |ss|
ss.source_files = "ToolsModule/Classes/Home/compass/*.{h,m}"
end
end
主要说明几个点:
1). source_files
source_files
源码仓库地址(s.source)下,资源文件(要提供给别人使用的所有文件)的路径。文件路径是以
.podspec
文件所在层级开始的。-
source_files写法说明 (以物理路径为准)
way1:直接指定文件名source_files = 'XXX/XXX/fileName.swift'
way2:目录下所有符合的文件source_files = 'XXX/XXX/*.swift'
way3: 指定文件夹下所有符合条件的文件source_files = 'XXX/XXX/**/*.{h,m}'
way4: 指定文件夹下所有文件source_files = 'XXX/XXX/**/*'
**/*
表示XXX/XXX/
目录及其子目录下所有文件**表示匹配该目录以及所有子目录,*.png表示所有以.png为扩展名的图片文件。
2). dependency 依赖三方的配置
- 依赖公共库。
s.dependency 'SnapKit'
#当前依赖库,pod install时会自动下载该库(注意:没有=
) - 依赖私有库。
s.dependency 'MCPageViewController'
需要在podfile
文件中指定存放podspec文件的仓库地址(包括公有库)
source 'https://github.com/CocoaPods/Specs.git' #官方仓库地址
source 'https://gitee.com/mancong/MyPublicRepo.git' #私有仓库地址
- 如果有依赖私有库情况,检验podspec文件不通过的情况。请使用:
pod spec lint --sources='spec仓库的地址
如有多个用,
隔开。如果公有库,地址写https://github.com/CocoaPods/Specs.git
比如依赖了两个库MCPageViewController (私有)
和SnapKit (共有)
pod spec lint --sources='https://github.com/mancongiOS/MCPageViewControllerRepo.git,https://github.com/CocoaPods/Specs.git' --allow-warnings
--sources
: 指定文件源
--allow-warnings
: 允许源文件中有警告的存在
因为CocoaPods会默认是官方地址下查找资源。但是私有库资源不在官方地址下的,所以要指定源地址。
3). 如何做文件夹层级?
s.subspec 'LevelDevice' do |ss|
ss.source_files = "ToolsModule/Classes/Home/LevelDevice/*.{h,m}"
ss.dependency 'ToolsModule/compass' #依赖本库的其他子库
end
子库的依赖是独立的,如果父库已经依赖了,子库可以不必依赖。注意依赖其他子subspec的情况,具体看上面提供的podspec示例文件
4). 如何关联资源文件?
因为资源不在主命名空间下,所以需要特别处理一下。
- 先将资源打包为Bundle
s.ios.resource_bundle = { 'ToolsModuleBundle' => 'ToolsModule/Assets/Home/**/*.{png,jpg}' }
ToolsModuleBundle
是自己命名的bundle名称。提交后会自动生成一个 Resources
文件夹,里面包含了资源文件。
- 如何在不同命名空间下加载
资源以及打包成一个bundle了,如何在pods库中使用呢?
@objc extension Bundle {
/**
* 加载指定bundle下的图片资源
* 在哪个pod下的哪个bundle下的image
*/
public static func mc_loadImage(_ imageName: String, from bundleName: String, in podName: String) -> UIImage? {
var associateBundleURL = Bundle.main.url(forResource: "Frameworks", withExtension: nil)
associateBundleURL = associateBundleURL?.appendingPathComponent(podName)
associateBundleURL = associateBundleURL?.appendingPathExtension("framework")
if associateBundleURL == nil {
print("获取bundle失败")
return nil
}
let associateBunle = Bundle.init(url: associateBundleURL!)
associateBundleURL = associateBunle?.url(forResource: bundleName, withExtension: "bundle")
if associateBundleURL != nil {
let bundle = Bundle.init(url: associateBundleURL!)
let scale = Int(UIScreen.main.scale)
// 适配2x还是3x图片
let name = imageName + "@" + String(scale) + "x"
let path = bundle?.path(forResource: name, ofType: "png")
if path == nil {
print("获取bundle失败")
return nil
}
let image1 = UIImage.init(contentsOfFile: path!)
return image1
} else {
return nil
}
}
}
// 使用
let image1 = Bundle.mc_loadImage("图片名", from: "命名的bundle名字", in: "库名字")
5). 编写swift版本库注意事项
- 配置swift的版本
s.swift_version = '4.0'
因为不同版本对应不同的swift方法。比如privite
这个作用域修饰词3.0上就没有。 - 配置iOS的部署版本
s.ios.deployment_target = '8.0'
- 给swift文件中的类名和方法添加作用域修饰词
需要给类加上修饰词,只允许访问不能继承就用public
,如何允许继承就用open
修饰,不允许被继承就用public
修饰。如果不用这两个关键词修饰的类或者方法,都不会被其他module访问到。
6). 如何校验podspec文件
-
pod lib lint
只从本地验证你的pod能否通过验证。 -
pod spec lint
从本地和远程验证你的pod能否通过验证,建议使用这个。 -
--use-libraries
依赖库(s.dependency)中 如果包含.a
文件,验证的时候出现错误。加上这个来让验证通过。 -
--allow-warnings
如何库代码中有警告导致通不过验证。加上这个忽略警告 - 私有库的验证
使用pod spec lint去验证私有库能否通过验证时应该,应该要添加--sources并在podfile文件中指定repo的地址,不然会出现找不到repo的错误。
pod spec lint --sources='私有仓库repo地址1,私有仓库repo地址1,公有库的地址'
用英文逗号隔开 ,公有库地址为:https://github.com/CocoaPods/Specs repo的地址为存放podspec文件的仓库,podfile文件中指定repo地址
podspec准备就绪,如何发布出去呢?
1. 为什么要发布podspec文件?
我们已经将代码源用podspec文件管理起来了。要让其他人能下载使用你的代码,就要让他找到podspec文件,所以我们要讲podspec文件放在网络上托管起来。
- 公有库:将podspec放在cocoPods官方提供的仓库https://github.com/CocoaPods/Specs.git上托管
- 私有库: 将podspec放在个人或者公司git仓库托管。
ps: 也就是说,一份库,需要两个git仓库来托管,一个是代码源的仓库,一个是podspec的仓库
3. 发布前的准备。
- 在Example目录下,
pod install
一下。 - 回到根目录(podspec所在层级目录),对podspec文件进行校验。
- 正常提交代码并打上标签。
// Example目录下
pod install
// 回到项目根目录下
git add -A
git commit -m "此次内容"
git push
git tag 0.0.1
git push origin --tags
发布前的准备工作完成。
2. 发布podspec文件到公有库中
- 注册cocoaPods
终端执行:$ pod trunk register 邮箱地址 '用户名' --verbose
这里我们一般使用github邮箱和用户名, 然后在你的邮箱中会收到确认邮件, 在浏览器中点击链接确认即注册成功;
- 验证cocoaPods
确保打开了邮件中的链接之后(正常加载出来就行),继续执行命令
终端执行: $ pod trunk me
- 发布
终端执行: $ pod trunk push XXX.podspec
该命令执行的过程
a.更新本地 pods库 ~/.cocoaPods.repo/master
b.验证*.podspec格式是否正确
c.将 *.podspec 文件转成 JSON 格式
d.对 master 仓库进行合并、提交
- 完成发布操作
发布成功,会有成功的提示(包含:日期,链接,Tell your friends)。
3. 发布私有库
创建配置仓(用来存储代码的podspec文件,即上面创建的podspec文件)。创建时别忘记选择MIT License许可证。
将配置仓链接到本地repo
pod repo add 配置仓名(自己起的仓库名字) 配置仓地址(仓库的git地址)
示例:pod repo add MCCCSpec https://github.com/mancongiOS/MCCCCSpec.git
说明:此命令在新开的终端中执行,用完即可关闭发布私有库
pod repo push 项目配置库名 项目代码库.podspec
示例:pod repo push MCCCSpec MCCC.podspec
说明:此命令在原终端中执行,即podspec同级路径下-
发布完成
-
附录: 查看repos文件夹
open ~/.cocoapods/repos
master对应的公有库版本信息
非master对应的是私有库版本信息
发布完成去使用
-
pod search + 库名
如何搜索不到,请更新本地库的索引文件。
open ~/Library/Caches/CocoaPods
删除该目录下的search_index.json
文件。
本地会保存一个repo镜像,search操作只是为了方便会到本地去检索,对应的应该会有个策略,看起来应该就是缓存里这个plist了,以后如果repos更新了,plist里面没有更新,那么就搜索不到。 - podfile中使用
pod 'MCPageViewController'
报错
在podfile文件中添加资源文件路径
source 'https://github.com/CocoaPods/Specs.git' #官方仓库地址
source ‘https://github.com/mancongiOS/MCPageViewControllerRepo.git’ #私有仓库地址
-
pod install
时报错版本信息错误
更新版本pod update 库名
或pod repo update
(不推荐使用,会更新所有的第三方库)
常见发布问题
-
[!] The repo
MyPublicRepoat ../../../.cocoapods/repos/MyPublicRepo is not clean
解决办法
方法1:
cd ~/.cocoapods/repos
cd MyRepo(报错的库名字)
git clean -f
方法2:
pod repo update MyRepo
如果还不可以那么先删除原有的版本库再重新安装版本库,然后执行更新命令
pod repo remove MyRepo
pod repo add MyRepo https://xxx.git
pod repo push MyRepo XXX.podspec
联系作者
QQ群: 316879774