cocoaPods的使用——让自己的开源代码支持cocoaPod
一、本文目的
通过一个实际的案例,讲述如何让自己的开源代码和框架支持cocoaPods,以便让其它用户使用cocoaPods做第三方库的依赖时,可以搜索并加载你的开源代码和框架。
二、该做的准备
- github账户,你需要将要支持cocoaPods的代码和框架开源到这个网站上;
- 终端,大部分的操作都是在终端进行的;
- Xcode。
三、基本步骤
- 首先在github上创建一个仓库SCMoveView。创建仓库时点选创建README.md文件,并添加语言为Objective-C语言的.ignore文件和MIT类型的License文件;
- 使用终端或者SourceTree软件,将该仓库下载到本地;
- 在第2步下载到本地的仓库中,新建一个工程文件SCMoveViewDemo,在该工程中编写要开源的代码库(这些代码库应该是独立于根视图控制器之外的类文件),如我在SCMoveViewDemo工程中创建的SCMoveView.h和SCMoveView.m文件。
- 单独存放要开源的文件;
- 创建.podspec文件;
- 编辑.podspec文件的基本属性值;
- 使用终端或者SourceTree软件将最新的本地仓库上传到github网站对应的仓库中;
- 创建开源库本地tag值,并将tag值上传到github网站对应的仓库中;
- 使用终端验证.podspec文件;
- 使用终端注册trunk(如果没有注册过的话)
- 使用终端提交.podspec文件到cocoaPods仓库;
- 检查cocoaPods仓库中是否有我们已经提交的开源代码库。
四、详细步骤
第1~3步骤读者可参考其它文章,本文不再赘述。
4. 单独备份要开源的文件
我们在与SCMoveViewDemo目录同级的目录下,创建一个名为SCMoveView的目录,然后将我们的SCMoveView.h和SCMoveView.m文件copy一份到这个目录下,效果如下图所示。
图15. 创建.podspec文件;
- 打开终端,进入我们从github仓库中下载下来的SCMoveView目录,如下图所示:
- 创建.podspec文件,我们将文件命名为SCMoveView.podspec。在终端输入如下代码并回车创建SCMoveView.podspec文件(注意,图片中创建podspec的方法写错了!!!):
pod spec create SCMoveView
如下图所示:
图3此时进入SCMoveView目录,会发现已经创建好的SCMoveView.podspec文件,如下图所示:
图46. 编辑.podspec文件的基本属性值
使用Xcode打开我们刚才创建的SCMoveView.podspec文件,找到对应的位置,按照如下示例编辑响应的值:
Pod::Spec.new do |s|
s.name = "SCMoveView"
s.version = "0.0.3"
s.summary = "SCMoveView."
s.description = <<-DESC
SCMoveView is cool.
DESC
s.homepage = "https://github.com/SC-Stefen/SCMoveView"
s.license = "MIT"
s.author = { "Stefen" => "1828850812@qq.com" }
s.platform = :ios, "9.0"
s.source = { :git => "https://github.com/SC-Stefen/SCMoveView.git", :tag => "#{s.version}" }
s.source_files = "SCMoveView"
s.framework = "UIKit"
s.requires_arc = true
end
以上内容是基本的配置,每一行代表的意思简单解释一下:
1>
Pod::Spec.new do |s|
保持默认即可,其中|s|表示本.podspec文件里面配置的母根都是以s.xx开头,这在下面的代码中可以看出。
2>
s.name
开源库的名称,也即执行pod search时输入的名称,该名称一般默认与.podspec文件保持一致。
3>
s.version
开源库的版本号。一般开源库如果有更新,都会上传为新的版本号。默认是从0.0.1开始,也可以设置为自己的值,但这些值最好都有传承性和递进性。
4>
s.summary
提交信息,描述本次提交代码的内容。
5>
s.description
描述信息,一般这个值不能与s.summary值一样,也不能比s.summary值少,否则在进行第9步时会提出警告(虽然警告不影响程序的执行)。
6>
s.homepage
github中该开源库对应的仓库的地址。
7>
s.license
许可证,一般设置为MIT(我们在github上创建SCMoveView仓库时,选择的也是MIT类型的License)。
8>
s.author
作者信息。
9>
s.platform
该开源框架支持的平台及系统版本。
10>
s.source
该开源框架远程仓库地址,其属性一个是地址,另外一个是远程仓库中该开源库的版本。一般远程仓库中的版本与.podspec文件中设置的s.version版本一致(我们将在第8条说明如何创建开源库本地tag值,并上传到github上)。
11>
s.source_files
我们在哪个源文件下可以找到要开源的文件。这是一个相对于.podspec文件的相对路径,因为我们将SCMoveView.h和SCMoveView.m文件直接放在了SCMoveView目录下,所以这个属性的值我们直接设置为SCMoveView。我们将在第五大节的扩展内容中,介绍设置多级目录,并将多级目录上传到cocoaPods上。
12>
s.framework
该开源库支持的框架类型,此处设置为UIKit即可。
13>
s.requires_arc = true
如果该属性值设置为true,代表该开源库支持ARC内存管理。
第7条将本地代码库push到github远程代码库中的方法可参考其它文章,本文不再赘述。
8. 创建开源库本地tag值,并将tag值上传到github网站对应的仓库中
打开终端,按照第5步骤第1条的方法,进入从github中下载的SCMoveView目录。然后输入
git tag 0.0.3
并回车,就将SCMoveView的tag设置为0.0.3(该值与.podspec文件中的s.version值一样),如下图所示:
图5
我们可以输入
git tag
代码检查tag是否设置完成。
接下来,我们在终端继续输入如下代码并回车,然后输入SSH密钥,将本地的tag值上传到github对应的仓库里面:
git push origin --tags
如下图所示:
图6
9. 使用终端验证.podspec文件
仍然在上一步介绍的SCMoveView路径下,在终端输入如下代码并回车来验证.podspec文件:
pod spec lint SCMoveView.podspec
如果SCMoveView.podspec没有问题,则出现如下图所示绿色字体的提示,说明SCMoveView.podspec验证成功:
图7
10. 使用终端注册trunk(如果没有注册过的话)
还是在上述的SCMoveView路径下,我们先用如下代码检查一下我们是否已经为这个要开源的代码库注册过trunk:
pod trunk me
如果没有出现如下图的信息,说明还没有注册:
图8如果没有注册,就继续在终端输入如下代码并回车,来注册trunk:
pod trunk register your_emai_address@qq.com "Your trunk Name"
我们只需要输入email地址及用户名即可。注册后进入该出填写的邮箱,点击系统发送的确认注册的链接即可完成注册操作。再次使用
pod trunk me
会发现,已经有了注册信息了。
11. 使用终端提交.podspec文件到cocoaPods仓库
⚠️这步操作会非常缓慢,建议在内地的朋友使用VPN翻墙一下。⚠️
注册trunk之后,我们继续在终端输入如下代码并回车:
pod trunk push SCMoveView.podspec
等待一段时间之后,如果终端出现如下界面,说明我们的开源库上传成功(因为某些原因,图9和图10显示的是0.0.4版本的):
图9
此时,在终端输入如下代码并回车:
pod search SCMoveView
就可以在cocoaPods中搜索到我们上传的开源库,如下图所示:
图10
五、增加开源库的其它依赖框架及工程目录模块化设计
我们以AFNetworking框架为例,它所依赖的其它框架及模块化工程目录如下图所示:
图11
从上图会看到,AFNetworking还依赖NSURLSession、Reachability、Security等框架,每一个框架都被放置在自己的文件夹下面,这样层次结构非常明显的设计是如何完成的呢?
首先,我们需要让我们的开源库支持子模块化,我们在.podspec文件中描述开源库源文件的代码中增加一句“submodules => true”描述就可以完成该工作(以AFNetworking开源框架为例,下同):
s.source = { :git => 'https://github.com/AFNetworking/AFNetworking.git', :tag => s.version, :submodules => true }
如果不需要支持子模块化,那么s.source的值应该如下:
s.source = { :git => 'https://github.com/AFNetworking/AFNetworking.git', :tag => s.version}
然后,我们在“Platform Specifics”一类目中,增加如下的代码:
s.subspec 'Serialization' do |ss|
ss.source_files = 'AFNetworking/AFURL{Request,Response}Serialization.{h,m}'
ss.public_header_files = 'AFNetworking/AFURL{Request,Response}Serialization.h'
ss.watchos.frameworks = 'MobileCoreServices', 'CoreGraphics'
ss.ios.frameworks = 'MobileCoreServices', 'CoreGraphics'
ss.osx.frameworks = 'CoreServices'
end
s.subspec 'Security' do |ss|
ss.source_files = 'AFNetworking/AFSecurityPolicy.{h,m}'
ss.public_header_files = 'AFNetworking/AFSecurityPolicy.h'
ss.frameworks = 'Security'
end
s.subspec 'Reachability' do |ss|
ss.ios.deployment_target = '7.0'
ss.osx.deployment_target = '10.9'
ss.tvos.deployment_target = '9.0'
ss.source_files = 'AFNetworking/AFNetworkReachabilityManager.{h,m}'
ss.public_header_files = 'AFNetworking/AFNetworkReachabilityManager.h'
ss.frameworks = 'SystemConfiguration'
end
s.subspec 'NSURLSession' do |ss|
ss.dependency 'AFNetworking/Serialization'
ss.ios.dependency 'AFNetworking/Reachability'
ss.osx.dependency 'AFNetworking/Reachability'
ss.tvos.dependency 'AFNetworking/Reachability'
ss.dependency 'AFNetworking/Security'
ss.source_files = 'AFNetworking/AF{URL,HTTP}SessionManager.{h,m}'
ss.public_header_files = 'AFNetworking/AF{URL,HTTP}SessionManager.h'
end
s.subspec 'UIKit' do |ss|
ss.ios.deployment_target = '7.0'
ss.tvos.deployment_target = '9.0'
ss.dependency 'AFNetworking/NSURLSession'
ss.public_header_files = 'UIKit+AFNetworking/*.h'
ss.source_files = 'UIKit+AFNetworking'
end
针对“NSURLSession”我们做一个详细的解释。“NSURLSession”的描述看起来如下所示:
s.subspec 'NSURLSession' do |ss|
ss.dependency 'AFNetworking/Serialization'
ss.ios.dependency 'AFNetworking/Reachability'
ss.osx.dependency 'AFNetworking/Reachability'
ss.tvos.dependency 'AFNetworking/Reachability'
ss.dependency 'AFNetworking/Security'
ss.source_files = 'AFNetworking/AF{URL,HTTP}SessionManager.{h,m}'
ss.public_header_files = 'AFNetworking/AF{URL,HTTP}SessionManager.h'
end
1.
s.subspec 'NSURLSession' do |ss|
这句话表示,我们的开源库要添加一个子模块:
s.subspec
表示要添加子模块的名称定义,s是自身的开源库的定义。
'NSURLSession'
表示子模块的显示名称(及加载后显示在Xcode中的文件夹名称)。
do |ss|
表示我们所增加的子模块定义为ss,在下面的描述中均以ss.开头,而非s.开头。
2.
ss.dependency 'AFNetworking/Serialization' ss.ios.dependency 'AFNetworking/Reachability' ss.osx.dependency 'AFNetworking/Reachability' ss.tvos.dependency 'AFNetworking/Reachability' ss.dependency 'AFNetworking/Security' ss.source_files = 'AFNetworking/AF{URL,HTTP}SessionManager.{h,m}' ss.public_header_files = 'AFNetworking/AF{URL,HTTP}SessionManager.h'
这段话描述的是子模块所包含的文件名,以及依赖的该开源库(AFNetworking)中其它的子模块。
ss.dependency
表示要依赖的其它子模块,后面跟上子模块包含文件的相对路径。
ss.source_files
表示该子模块(NSURLSession)所包含文件的相对路径。
ss.public_header_files
表示该子模块(NSURLSession)所包含头文件的相对路径。
3.
end
结束。每一个子模块的定义都需要加上一个end表示结束。
我们看一下AFNetworing开源库本身的目录结构(将AFNetworing下载到电脑上之后打开看到的目录结构),如下图所示:
图12可以看到,作者将所有的子模块所包含的文件与AFNetworing.h文件放到了一个目录下。如果我们在本地机器上,就把各子模块单独创建一个文件夹,然后把子模块所包含的文件放到这个文件夹里面,如下图所示:
图13这时,我们在编写.podspec文件中子模块的源文件路径时,可以改成如下的写法:
ss.source_files = 'AFNetworking/**/AF{URL,HTTP}SessionManager.{h,m}'
**表示在相对路径AFNetworking文件夹下面,还有一层文件夹,然后才能到我们的子模块所包含的文件。