整体流程
整体先说明一下创建一个私有的podspec包括如下那么几个步骤:
- 创建并设置一个私有的Spec Repo。
- 创建Pod的所需要的项目工程文件,并且有可访问的项目版本控制地址。
- 创建Pod所对应的podspec文件。
- 本地测试配置好的podspec文件是否可用。
- 向私有的Spec Repo中提交podspec。
- 在个人项目中的Podfile中增加刚刚制作的好的Pod并使用。
- 更新维护podspec。
1. 创建私有Spec Repo
Spec Repo是所有的Pods的一个索引,就是一个容器,所有公开的Pods都在这个里面,它实际是一个Git仓库remote端在GitHub上,但是当你使用了Cocoapods后它会被clone到本地的~/.cocoapods/repos目录下,可以进入到这个目录看到master文件夹就是这个官方的Spec Repo了。这个master目录的结构大概就是这个样子的:
Specs - [SPEC_NAME] - [VERSION] - [SPEC_NAME].podspec
首先,创建一个 Git仓库,这个仓库你可以创建私有的也可以创建公开的,不过既然私有的Spec Repo,还是创建私有的仓库吧,需要注意的就是如果项目中有其他同事共同开发的话,你还要给他这个Git仓库的权限。
创建完成之后终端中执行以下命令:
pod repo add [私有Spec RepoName] [仓库地址]
比如: pod repo add WTSpecs https://coding.net/wtlucky/WTSpecs.git
此时如果成功的话进入到 ~/.cocoapods/repos 目录下就可以看到WTSpecs这个目录了。至此第一步创建私有Spec Repo完成。
Note:如果有其他合作人员共同使用这个私有Spec Repo的话在他有对应Git仓库的权限的前提下执行相同的命令添加这个Spec Repo即可。
2. 创建Pod项目工程文件
这个第二步没有什么好介绍的,如果是有现有的组件项目,并且在Git的版本管理下,那么这一步就算完成了,可以直接跳过这个步骤了。
如果你的组件还在你冗余庞大的项目中,需要拆分出来或者需要自己从零开始创建一个组件库,那么我建议你使用Cocoapods提供的一个工具将第二步与第三步结合起来做。
现在来说一下这个工具,相关的文档介绍是Using Pod Lib Create ,就拿我创建的podTestLibrary为例子具体讲一下这里是如何操作的,先cd到要创建项目的目录然后执行:
pod lib create podTestLibrary
然后,等待一会儿, 它会问您几个问题?
- What platform do you want to use?? [ iOS / macOS ]
- What language do you want to use?? [ Swift / ObjC ]
- Would you like to include a demo application with your library? [ Yes / No ]
- Which testing frameworks will you use? [ Specta / Kiwi / None ]
- Would you like to do view based testing? [ Yes / No ]
- What is your class prefix?
翻译下来,按自己需求回答即可。
然后,就可以看到在刚才的目录下面,成功生成了以下文件
$ tree PodTestLibrary -L 2
PodTestLibrary
├── Example #demo APP
│ ├── PodTestLibrary
│ ├── PodTestLibrary.xcodeproj
│ ├── PodTestLibrary.xcworkspace
│ ├── Podfile #demo APP 的依赖描述文件
│ ├── Podfile.lock
│ ├── Pods #demo APP 的依赖文件
│ └── Tests
├── LICENSE #开源协议 默认MIT
├── Pod #组件的目录
│ ├── Assets #资源文件
│ └── Classes #类文件
├── PodTestLibrary.podspec #第三步要创建的podspec文件
└── README.md #markdown格式的README
以上是项目生成的目录结构及相关介绍。
接下来就是向Pod文件夹中添加库文件和资源,并配置podspec文件,我把一个网络模块的共有组件放入Pod/Classes中,然后进入Example文件夹执行pod update命令,再打开项目工程可以看到,刚刚添加的组件已经在Pods子工程下Development Pods/PodTestLibrary中了,然后编辑demo工程,测试组件,我并没有使用提供的测试框架进行测试,这里就先不介绍了。
Note:这里需要注意的是每当你向Pod中添加了新的文件或者以后更新了podspec的版本都需要重新执行一遍pod update命令。
测试无误后需要将该项目添加并推送到远端仓库,并编辑podspec文件。
通过Cocoapods创建出来的目录本身就在本地的Git管理下,我们需要做的就是给它添加远端仓库,同样去GitHub或其他的Git服务提供商那里创建一个私有的仓库,拿到SSH地址,然后cd到PodTestLibrary目录
git add .
git commit -s -m "Initial Commit of Library"
git remote add origin [email protected]:wtlucky/podTestLibrary.git #添加远端仓库
git push origin master #提交到远端仓库
因为podspec文件中获取Git版本控制的项目还需要tag号,所以我们要打上一个tag,
git tag -m "first release" "0.1.0"
git push --tags #推送tag到远端仓库
做完这些就可以开始编辑podspec文件了,它是一个Ruby的文件,把编辑器的格式改成Ruby就能看到语法高亮,下面我贴上我的podspec文件,并在后面以注释的形式说明每个字段的含义,没有涉及到的字段可以去官方文档查阅
| `01`|`Pod::Spec.``new` `do` `|s|` |
| `02` | `s.name = ``"PodTestLibrary"` `#名称` |
| `03` | `s.version = ``"0.1.0"` `#版本号` |
| `04` | `s.summary = ``"Just Testing."` `#简短介绍,下面是详细介绍` |
| `05` | `s.description = <<-DESC` |
| `06` | `Testing Private Podspec.` |
| `07` | |
| `08` | `* Markdown format.` |
| `09` | `* Don't worry about the indent, we strip it!` |
| `10` | `DESC` |
| `11` | `s.homepage = ``"[https://coding.net/u/wtlucky/p/podTestLibrary](https://coding.net/u/wtlucky/p/podTestLibrary)"` `#主页,这里要填写可以访问到的地址,不然验证不通过` |
| `12` | `# s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2" #截图` |
| `13` | `s.license = ``'MIT'` `#开源协议` |
| `14` | `s.author = { ``"wtlucky"` `=> ``"[email protected]"` `} ``#作者信息` |
| `15` | `s.source = { :git => ``"[https://coding.net/wtlucky/podTestLibrary.git](https://coding.net/wtlucky/podTestLibrary.git)"``, :tag => ``"0.1.0"` `} ``#项目地址,这里不支持ssh的地址,验证不通过,只支持HTTP和HTTPS,最好使用HTTPS` |
| `16` | `# s.social_media_url = '[https://twitter.com/' #多媒体介绍地址` |
| `17` | |
| `18` | `s.platform = :ios, ``'7.0'` `#支持的平台及版本` |
| `19` | `s.requires_arc = ``true` `#是否使用ARC,如果指定具体文件,则具体的问题使用ARC` |
| `20` | |
| `21` | `s.source_files = ``'Pod/Classes/**/*'` `#代码源文件地址,**/*表示Classes目录及其子目录下所有文件,如果有多个目录下则用逗号分开,如果需要在项目中分组显示,这里也要做相应的设置` |
| `22` | `s.resource_bundles = {` |
| `23` | `'PodTestLibrary'` `=> [``'Pod/Assets/*.png'``]` |
| `24` | `} ``#资源文件地址` |
| `25` | |
| `26` | `s.public_header_files = ``'Pod/Classes/**/*.h'` `#公开头文件地址` |
| `27` | `s.frameworks = ``'UIKit'` `#所需的framework,多个用逗号隔开` |
| `28` | `s.dependency ``'AFNetworking'``, ``'~> 2.3'` `#依赖关系,该项目所依赖的其他库,如果有多个需要填写多个s.dependency` |
| `29` | `end ` |
编辑完podspec文件后,需要验证一下这个文件是否可用,如果有任何WARNING或者ERROR都是不可以的,它就不能被添加到Spec Repo中,不过xcode的WARNING是可以存在的,验证需要执行一下命令
pod lib lint
当你看到
1 -> PodTestLibrary (0.1.0)
2
3 PodTestLibrary passed validation.
时,说明验证通过了,不过这只是这个podspec文件是合格的,不一定说明这个Pod是可以用的,我们需要在本地做一下验证,这就是第四步的内容了,第四步在具体说明。
3. 创建podspec文件
如果从第二步过来,已经有了现成的项目,那么就需要给这个项目创建一个podspec文件,创建它需要执行Cocoapods的另外一个命令:
pod spec create PodTestLibrary [email protected]:wtlucky/podTestLibrary.git
执行完之后,就创建了一个podspec文件,他其中会包含很多内容,可以按照我之前介绍的进行编辑,没用的删掉。编辑完成之后使用验证命令验证一下
pod lib lint
验证无误就可以进入下一步了。
4. 本地测试podspec文件
我们可以创建一个新的项目,在这个项目的Podfile文件中直接指定刚才创建编辑好的podspec文件,看是否可用。 在Podfile中我们可以这样编辑,有两种方式
1 platform :ios, '7.0'
2
3 pod 'PodTestLibrary', :path => '~/code/Cocoapods/podTest/PodTestLibrary' #指定路径
4 pod 'PodTestLibrary', :podspec => '~/code/Cocoapods/podTest/PodTestLibrary/PodTestLibrary.podspec' #指定podspec文件
然后执行pod install命令安装依赖,打开项目工程,可以看到库文件都被加载到Pods子项目中了,不过它们并没有在Pods目录下,而是跟测试项目一样存在于Development Pods/PodTestLibrary中,这是因为我们是在本地测试,而没有把podspec文件添加到Spec Repo中的缘故。
在项目中编写代码,测试库文件无误后就可以开始下一步了,提交podspec到Spec Repo中。
5. 向Spec Repo提交podspec
向Spec Repo提交podspec需要完成两点一个是podspec必须通过验证无误,在一个就是删掉无用的注释(这个不是必须的,为了规范还是删掉吧)。 向我们的私有Spec Repo提交podspec只需要一个命令:
pod repo push WTSpecs PodTestLibrary.podspec #前面是本地Repo名字 后面是podspec名字
如果有warning 但是没有error,提示验证不通过可以增加忽略警告的参数:
pod repo push 本地repo名 NAME.podspec --verbose --use-libraries --allow-warnings
完成之后这个组件库就添加到我们的私有Spec Repo中了,可以进入到~/.cocoapods/repos/WTSpecs目录下查看:
1 .
2 ├── LICENSE
3 ├── PodTestLibrary
4 │ └── 0.1.0
5 │ └── PodTestLibrary.podspec
6 └── README.md
再去看我们的Spec Repo远端仓库,也有了一次提交,这个podspec也已经被Push上去了。
至此,我们的这个组件库就已经制作添加完成了,使用pod search命令就可以查到我们自己的库了:
1 $ pod search PodTestLibrary
2
3 -> PodTestLibrary (0.1.0)
4 Just Testing.
5 pod 'PodTestLibrary', '~> 0.1.0'
6 - Homepage: https://coding.net/u/wtlucky/p/podTestLibrary
7 - Source: https://coding.net/wtlucky/podTestLibrary.git
8 - Versions: 0.1.0 [WTSpecs repo]
这里说的是添加到私有的Repo,如果要添加到Cocoapods的官方库了,可以使用trunk工具,具体可以查看官方文档。
6. 使用制作好的Pod
在完成这一系列步骤之后,我们就可以在正式项目中使用这个私有的Pod了需要在项目的Podfile里增加以下一行代码:
pod 'PodTestLibrary', '~> 0.1.0'
并且在podfile文件上面加入两个source地址:
source 'https://github.com/CocoaPods/Specs.git' // 官方的
source 'https://coding.net/wtlucky/podTestLibrary.git' // 自己的仓库git地址
然后执行pod update,更新库依赖,然后打开项目可以看到,我们自己的库文件已经出现在Pods子项目中的Pods子目录下了,而不再是Development Pods。
7. 更新维护podspec
最后再来说一下制作好的podspec文件后续的更新维护工作,比如如何添加新的版本,如何删除Pod。
我已经制作好了PodTestLibrary的0.1.0版本,现在我对他进行升级工作,这次我添加了更多的模块到PodTestLibrary之中,包括工具类,底层Model及UIKit扩展等,这里又尝试了一下subspec功能,给PodTestLibrary创建了多个子分支。
具体做法是先将源文件添加到Pod/Classes中,然后按照不同的模块对文件目录进行整理,因为我有四个模块,所以在Pod/Classes下有创建了四个子目录,完成之后继续编辑之前的PodTestLibrary.podspec,这次增加了subspec特性
| `01` | `Pod::Spec.``new` `do` `|s|` |
| `02` | `s.name = ``"PodTestLibrary"` |
| `03` | `s.version = ``"1.0.0"` |
| `04` | `s.summary = ``"Just Testing."` |
| `05` | `s.description = <<-DESC` |
| `06` | `Testing Private Podspec.` |
| `07` | |
| `08` | `* Markdown format.` |
| `09` | `* Don't worry about the indent, we strip it!` |
| `10` | `DESC` |
| `11` | `s.homepage = ``"[https://coding.net/u/wtlucky/p/podTestLibrary](https://coding.net/u/wtlucky/p/podTestLibrary)"` |
| `12` | `# s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2"` |
| `13` | `s.license = ``'MIT'` |
| `14` | `s.author = { ``"wtlucky"` `=> ``"[email protected]"` `}` |
| `15` | `s.source = { :git => ``"[https://coding.net/wtlucky/podTestLibrary.git](https://coding.net/wtlucky/podTestLibrary.git)"``, :tag => ``"1.0.0"` `}` |
| `16` | `# s.social_media_url = '[https://twitter.com/'` |
| `17` | |
| `18` | `s.platform = :ios, ``'7.0'` |
| `19` | `s.requires_arc = ``true` |
| `20` | |
| `21` | `#s.source_files = 'Pod/Classes/**/*'` |
| `22` | `#s.resource_bundles = {` |
| `23` | `# 'PodTestLibrary' => ['Pod/Assets/*.png']` |
| `24` | `#}` |
| `25` | `#s.public_header_files = 'Pod/Classes/**/*.h'` |
| `26` | |
| `27` | `s.subspec ``'NetWorkEngine'` `do` `|networkEngine|` |
| `28` | `networkEngine.source_files = ``'Pod/Classes/NetworkEngine/**/*'` |
| `29` | `networkEngine.public_header_files = ``'Pod/Classes/NetworkEngine/**/*.h'` |
| `30` | `networkEngine.dependency ``'AFNetworking'``, ``'~> 2.3'` |
| `31` | `end` |
| `32` | |
| `33` | `s.subspec ``'DataModel'` `do` `|dataModel|` |
| `34` | `dataModel.source_files = ``'Pod/Classes/DataModel/**/*'` |
| `35` | `dataModel.public_header_files = ``'Pod/Classes/DataModel/**/*.h'` |
| `36` | `end` |
| `37` |
| `38` | s.subspec 'CommonTools' do |commonTools|
| `39` | commonTools.source_files = 'Pod/Classes/CommonTools/**/*'
| `40` | commonTools.public_header_files = 'Pod/Classes/CommonTools/**/*.h'
| `41` | commonTools.dependency 'OpenUDID', '~> 1.0.0'
| `42` | end
| `43` |
| `44` | s.subspec 'UIKitAddition' do |ui|
| `45` | ui.source_files = 'Pod/Classes/UIKitAddition/**/*'
| `46` | ui.public_header_files = 'Pod/Classes/UIKitAddition/**/*.h'
| `47` | ui.resource = "Pod/Assets/MLSUIKitResource.bundle"
| `48` | ui.dependency 'PodTestLibrary/CommonTools'
| `49` | end
| `50` |
| `51` | s.frameworks = 'UIKit'
| `52` | #s.dependency 'AFNetworking', '~> 2.3'
| `53` | #s.dependency 'OpenUDID', '~> 1.0.0'
| `54` | 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 WTSpecs PodTestLibrary.podspec
之后再次到~/.cocoapods/repos/WTSpecs目录下查看
01 .
02 ├── LICENSE
03 ├── PodTestLibrary
04 │ ├── 0.1.0
05 │ │ └── PodTestLibrary.podspec
06 │ └── 1.0.0
07 │ └── PodTestLibrary.podspec
08 └── README.md
09
10 3 directories, 4 files
已经有两个版本了,使用pod search查找得到的结果为
01 $ pod search PodTestLibrary
02
03 -> PodTestLibrary (1.0.0)
04 Just Testing.
05 pod 'PodTestLibrary', '~> 1.0.0'
06 - Homepage: https://coding.net/u/wtlucky/p/podTestLibrary
07 - Source: https://coding.net/wtlucky/podTestLibrary.git
08 - Versions: 1.0.0, 0.1.0 [WTSpecs repo]
09 - Sub specs:
10 - PodTestLibrary/NetWorkEngine (1.0.0)
11 - PodTestLibrary/DataModel (1.0.0)
12 - PodTestLibrary/CommonTools (1.0.0)
13 - PodTestLibrary/UIKitAddition (1.0.0)
完成这些之后,在实际项目中我们就可以选择使用整个组件库或者是组件库的某一个部分了,对应的Podfile中添加的内容为
1 platform :ios, '7.0'
2
3 pod 'PodTestLibrary/NetWorkEngine', '1.0.0' #使用某一个部分
4 pod 'PodTestLibrary/UIKitAddition', '1.0.0'
5
6 pod 'PodTestLibrary', '1.0.0' #使用整个库
最后介绍一下如何删除一个私有Spec Repo,只需要执行一条命令即可
pod repo remove WTSpecs
这样这个Spec Repo就在本地删除了,我们还可以通过
pod repo add WTSpecs [email protected]:wtlucky/WTSpecs.git
再把它给加回来。
如果我们要删除私有Spec Repo下的某一个podspec怎么操作呢,此时无需借助Cocoapods,只需要cd到~/.cocoapods/repos/WTSpecs目录下,删掉库目录
wtlucky@wtluckydeMacBook-Pro:~/.cocoapods/repos/WTSpecs$ rm -Rf PodTestLibrary
然后在将Git的变动push到远端仓库即可
1 wtlucky@wtluckydeMacBook-Pro:~/.cocoapods/repos/WTSpecs$ git add --all .
2 wtlucky@wtluckydeMacBook-Pro:~/.cocoapods/repos/WTSpecs$ git ci -m "remove unuseful pods"
3 wtlucky@wtluckydeMacBook-Pro:~/.cocoapods/repos/WTSpecs$ git push origin master