CocoaPods 开源库的制作过程:
- 添加私有Pod仓库,用来存储私有Pod库的podspec文件,类似CocoaPods的官方repo库(~/.cocoapods/repos)
- 创建私有Pod库的podspec文件(分全新创建和已存在工程两种情况)
- 编辑podspec文件
- 测试podspec文件是否可用
- 本地测试podspec文件
- 向私有Pod库提交podspec文件
- 添加到CocoaPods 官方库
- Pod库的更新维护
1. 添加私有Pod仓库
在 GitHub 创建一个 MySpecs 的空仓库,将远端的私有Specs仓库clone到本地.cocoapods目录下:
$ pod repo add MySpecs https://github.com/Wanlima/MySpecs.git
删除私有Pod仓库:
$ pod repo remove MySpecs
2. 创建podspec文件
一、 通过模板创建Pod项目工程文件,会包含一个podspec文件,不需要单独创建:(如果已有组件项目且在Git的版本管理下,可以直接进行入第二步)
$ pod lib create podTestLibrary
$ git add .
$ git commit -s -m "Initial Commit of Library"
#添加远端仓库
$ git remote add origin https://github.com/Wanlima/PodTestLibary.git
$ git push origin master
二、不是通过模板创建的Pod项目工程文件,cd到工程文件目录下 ,在终端执行命令:(如果通过模板命令生成,已经存在podspec文件,跳过这一步)
$ pod spec create PodTestLibary https://github.com/Wanlima/PodTestLibary.git
PodTestLibary是podspec文件名,如果要实现这一步,你需要先将你的工程push到远端。
3. 编辑podspec文件
用VSCode打开这个文件,安装Ruby和CocoaPods语法的插件,或者使用其他的文本编辑器打开,把编辑器的格式改成Ruby就能看到语法高亮,编辑podspec里面的信息(附:官方文档):
s.name = "xxxx" #库的名字
s.version = "0.0.1" #版本号,当私有库需要更新的时候只要修改这个值,自行维护
s.summay = "xxxxxx" #库的简介,pod search 显示在上面的介绍
s.description = "xxxxxxxx" #库的详细描述
s.homepage = "https://xxxx" #主页地址,pod search 会显示,一般填写仓库的地址就行了
s.license = "MIT" #开源协议,项目文件目录下需要有一个MIT开源协议文件
s.author = { "name" => "[email protected]" } #作者名字、邮箱
s.platform = :ios, "7.0" #库最低支持的系统版本
s.source = { :git => "https://github.com/CharlsPrince/CommonExtension.git", :tag => "#{s.version}" } #资源地址,pod install 的时候会根据这个地址去下载你的想要库,以及下载的版本,必须要跟s.version一致。
s.source_files = "xxxx" #这个很重要,指定资源文件,前缀就是.podspec文件当前路径,只用写之后的路径,如Class/*是指Class文件夹下的所有文件,但不包括子文件夹里面的文件、Class/**/*是指包含所有Class文件夹下的文件,包括子文件、Class/**/*.{h,m}是指包含所有Class文件夹下的后缀为.h或.m的文件,当然也可以指定文件。
s.requires_arc = true #是否支持arc
>>>>>以下是可选描述<<<<<
#s.resource = "icon.png" #资源文件,包括图片和xib文件
# s.dependency "JSONKit", "~> 1.4" #需要依赖的三方库
#s.framework = "SomeFramework" #需要依赖的框架
#s.public_header_files = '' #公开的头文件,如果不没公开,用户在用的时候可能引不到响应的头文件
s.subspec 'subFolder' do |ss|
ss.source_files = 'Class/xxx/**/*.{h,m}'
ss.public_header_files = "Class/xxx/**/*.{h}"
end #这个是子依赖库,因为如果我们只是用s.source_files来指定文件,那么用户在pod下来之后所有的文件都在同一个目录下,没有子文件夹,如果想要分下类,用s.subspec,每一个subspec可以分一个子文件夹,但是记得一定要将.h文件通过ss.public_header_files公开,不然有可能会找不到头文件。
4. 测试podspec文件是否可用:
编辑完podspec文件后,可在终端执行以下命令,检查文件是否可用:
$ pod lib lint
或
$ pod spec lint
注意项
- pod lib lint 所编译的源代码是来自于podspec所在目录而不是source所指定git地址
- pod spec lint 会联网校验,通过source中的git地址获取源代码,同时还会校验git地址上是否有对应version字段的tag
- 执行完,如果有错就根据错误修改podspec文件,通过则继续
- 基本通过的话你就直接可以使用这个库了,可以创建一个工程试验一下,在这个新建个工程里面新建一个Podfile文件并输入
当你看到
-> PodTestLibrary (0.1.0)
PodTestLibrary passed validation.
时,说明验证通过了,不过这只是这个podspec文件是合格的,不一定说明这个Pod是可以用的,我们需要在本地做一下验证。
5. 本地测试podspec文件
我们可以创建一个新的项目,在这个项目的Podfile文件中直接指定刚才创建编辑好的podspec文件,看是否可用。 在Podfile中我们可以这样编辑,有两种方式
platform :ios, '7.0'
pod 'PodTestLibrary', :path => '~/code/Cocoapods/podTest/PodTestLibrary' # 指定路径
pod 'PodTestLibrary', :podspec => '~/code/Cocoapods/podTest/PodTestLibrary/PodTestLibrary.podspec' # 指定podspec文件
然后执行pod install命令安装依赖,打开项目工程,可以看到库文件都被加载到Pods子项目中了,不过它们并没有在Pods目录下,而是跟测试项目一样存在于Development Pods/PodTestLibrary中,这是因为我们是在本地测试,而没有把podspec文件添加到Spec Repo中的缘故。
6. 向私有Pod库提交podspec文件:
因为podspec文件中获取Git版本控制的项目还需要tag号,所以我们要打上一个tag:
$ git tag -m "first release" 0.1.0
$ git push --tags #推送tag到远端仓库
然后
$ pod repo push MySpecs PodTestLibrary.podspec
如果提交成功,去 ~/.cocoapods/repos/MySpecs 文件夹下就能找到你创建的私有库了,当然,只是podspec文件哦,因为 ~/.cocoapods/repos/ 只是用来保存podspec文件.再去看我们的MySpecs远端仓库,也有了一次提交,这个podspec也已经被Push上去了。
至此,我们的这个组件库就已经制作添加完成了,使用pod search命令就可以查到我们自己的库了,相信怎么使用就不需要我在这里详细说明了。
7. 添加到Cocoapods的官方库
注册spec
并推送到远程仓库
使用trunk
进行注册
#填写验证邮箱,稍后通过邮件验证
pod trunk register [email protected] 'Name' --verbose
在终端会打印以下信息
opening connection to trunk.cocoapods.org:443...
opened
starting SSL for trunk.cocoapods.org:443...
SSL established
<- "POST /api/v1/sessions HTTP/1.1\r\nContent-Type: application/json; charset=utf-8\r\nAccept: application/json; charset=utf-8\r\nUser-Agent: CocoaPods/1.6.0.rc.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nHost: trunk.cocoapods.org\r\nContent-Length: 70\r\n\r\n"
<- "{\"email\":\"[email protected]\",\"name\":\"Passion\",\"description\":null}"
-> "HTTP/1.1 201 Created\r\n"
-> "Date: Thu, 21 Mar 2019 01:13:18 GMT\r\n"
-> "Connection: keep-alive\r\n"
-> "Strict-Transport-Security: max-age=31536000\r\n"
-> "Content-Type: application/json\r\n"
-> "Content-Length: 195\r\n"
-> "X-Content-Type-Options: nosniff\r\n"
-> "Server: thin 1.6.2 codename Doc Brown\r\n"
-> "Via: 1.1 vegur\r\n"
-> "\r\n"
reading 195 bytes...
-> "{\"created_at\":\"2019-03-21 01:13:18 UTC\",\"valid_until\":\"2019-07-27 01:13:18 UTC\",\"verified\":false,\"created_from_ip\":\"180.168.223.146\",\"description\":null,\"token\":\"5ef408511f16a93db35c2ae18e333d4b\"}"
read 195 bytes
Conn keep-alive
[!] Please verify the session by clicking the link in the verification email that has been sent to [email protected]
登录注册邮箱会收到一封认证邮件,点击链接完成认证,验证成功之后,使用终端命令进行推送
# pod trunk push 完整的.podspec文件名
pod trunk push PodTestLibary.podspec --allow-warnings
到这里CocoaPods依赖库就发布成功了。
这里说的是添加到私有的
Repo
,由于是示例就没有发布到Cocoapods
的官方库了,具体可以查看官方文档。
8. 更新维护podspec
我已经制作好了PodTestLibrary的0.1.0版本,现在我对他进行升级工作,这次我添加了更多的模块到PodTestLibrary之中,包括工具类,底层Model及UIKit扩展等,这里又尝试了一下subspec功能,给PodTestLibrary创建了多个子分支。
具体做法是先将源文件添加到Pod/Classes中,然后按照不同的模块对文件目录进行整理,因为我有四个模块,所以在Pod/Classes下有创建了四个子目录,完成之后继续编辑之前的PodTestLibrary.podspec,这次增加了subspec特性
Pod::Spec.new do |s|
s.name = "PodTestLibrary"
s.version = "1.0.0"
s.summary = "Just Testing."
s.description = <<-DESC
Testing Private Podspec.
* Markdown format.
* Don't worry about the indent, we strip it!
DESC
s.homepage = "https://coding.net/u/wtlucky/p/podTestLibrary"
# s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
s.license = 'MIT'
s.author = { "wtlucky" => "[email protected]" }
s.source = { :git => "https://coding.net/wtlucky/podTestLibrary.git", :tag => "1.0.0" }
# s.social_media_url = 'https://twitter.com/'
s.platform = :ios, '7.0'
s.requires_arc = true
#s.source_files = 'Pod/Classes/**/*'
#s.resource_bundles = {
# 'PodTestLibrary' => ['Pod/Assets/*.png']
#}
#s.public_header_files = 'Pod/Classes/**/*.h'
s.subspec 'NetWorkEngine' do |networkEngine|
networkEngine.source_files = 'Pod/Classes/NetworkEngine/**/*'
networkEngine.public_header_files = 'Pod/Classes/NetworkEngine/**/*.h'
networkEngine.dependency 'AFNetworking', '~> 2.3'
end
s.subspec 'DataModel' do |dataModel|
dataModel.source_files = 'Pod/Classes/DataModel/**/*'
dataModel.public_header_files = 'Pod/Classes/DataModel/**/*.h'
end
s.subspec 'CommonTools' do |commonTools|
commonTools.source_files = 'Pod/Classes/CommonTools/**/*'
commonTools.public_header_files = 'Pod/Classes/CommonTools/**/*.h'
commonTools.dependency 'OpenUDID', '~> 1.0.0'
end
s.subspec 'UIKitAddition' do |ui|
ui.source_files = 'Pod/Classes/UIKitAddition/**/*'
ui.public_header_files = 'Pod/Classes/UIKitAddition/**/*.h'
ui.resource = "Pod/Assets/MLSUIKitResource.bundle"
ui.dependency 'PodTestLibrary/CommonTools'
end
s.frameworks = 'UIKit'
#s.dependency 'AFNetworking', '~> 2.3'
#s.dependency 'OpenUDID', '~> 1.0.0'
end
因为我们创建了subspec所以项目整体的依赖dependency,源文件source_files,头文件public_header_files,资源文件resource等都移动到了各自的subspec中,每个subspec之间也可以有相互的依赖关系,比如UIKitAddition就依赖于CommonTools。
编辑完成之后,在测试项目里pod update一下,几个子项目都被加进项目工程了,写代码验证无误之后,就可以将这个工程push到远端仓库,并打上新的tag->1.0.0。
最后再次使用pod lib lint验证编辑好的podsepc文件,没有自身的WARNING或者ERROR之后,就可以再次提交到Spec Repo中了,命令跟之前是一样的
$ pod repo push MySpecs PodTestLibrary.podspec
之后再次到~/.cocoapods/repos/MySpecs目录下查看
.
├── LICENSE
├── PodTestLibrary
│ ├── 0.1.0
│ │ └── PodTestLibrary.podspec
│ └── 1.0.0
│ └── PodTestLibrary.podspec
└── README.md
3 directories, 4 files
已经有两个版本了,使用pod search查找得到的结果为
$ pod search PodTestLibrary
-> PodTestLibrary (1.0.0)
Just Testing.
pod 'PodTestLibrary', '~> 1.0.0'
- Homepage: https://github.com/Wanlima/podTestLibrary
- Source: https://github.com/Wanlima/podTestLibrary.git
- Versions: 1.0.0, 0.1.0 [MySpecs repo]
- Sub specs:
- PodTestLibrary/NetWorkEngine (1.0.0)
- PodTestLibrary/DataModel (1.0.0)
- PodTestLibrary/CommonTools (1.0.0)
- PodTestLibrary/UIKitAddition (1.0.0)
完成这些之后,在实际项目中我们就可以选择使用整个组件库或者是组件库的某一个部分了,对应的Podfile中添加的内容为
# 官方库
$ source 'https://github.com/CocoaPods/Specs.git'
# 私有库
$ source 'https://github.com/Wanlima/MySpecs.git'
platform :ios, '7.0'
pod 'PodTestLibrary/NetWorkEngine', '1.0.0' #使用某一个部分
pod 'PodTestLibrary/UIKitAddition', '1.0.0'
pod 'PodTestLibrary', '1.0.0' #使用整个库
如果我们要删除私有Spec Repo下的某一个podspec怎么操作呢,此时无需借助Cocoapods,只需要cd到~/.cocoapods/repos/WTSpecs目录下,删掉库目录
$ rm -Rf PodTestLibrary
然后在将Git的变动push到远端仓库即可
$ git add --all .
$ git ci -m "remove unuseful pods"
$ git push origin master
问题小结
- pod search 搜索不到
[!] Unable to find a pod with name, author, summary, or description matching `xxxLibary`
解决办法:
更新本地Pod仓库:
pod setup
删除搜索索引:
rm ~/Libary/Caches/Cocopods/search_index.json
重新搜索
提交本地podspec到Specs仓库的时候出错,提示repo 文件夹下的spec repo is not clean
方法一: cd到spec repo 文件夹下,执行 git clean -f
方法二:cd到spec repo 文件夹下,执行 git stash
方法三: 删除spec repo 下的Specs仓库,我这里的是“MySpecs”,然后重新从git上将私有仓库clone下来:
pod repo add MySpecs https://github.com/CharlsPrince/MySpecs.git