1、创建私有Spec Repo
Spec Repo是什么?它是所有的Pods的一个索引,就是一个容器,所有公开的Pods都在这个里面,它实际是一个Git仓库remote端在GitHub上,所以想要创建pod私有库,需要创建类似于master的私有Spec Repo,先在远程仓库创建一个工程JCLiveIOSSpecs,然后执行创建私有Spec Repo命令:
|
|
完成之后,进入到~/.cocoapods/repos目录下就可以看到JCLiveIOSSpecs这个目录了。
2、创建Pod项目工程文件
从零开始创建一个组件库,可以使用Cocoapods提供的工具Using Pod Lib Create ,先cd到要创建项目的目录然后执行
然后显示四个问题,1.是否需要一个例子工程;2.选择一个测试框架;3.是否基于View测试;4.类的前缀;4个问题的具体介绍可以去看官方文档。回答完4个问题他会自动执行pod install命令创建项目并生成依赖,项目结构如下:
3、创建私有库pod组件
所需要做的工作就是在相应的 Pods/Developemnt Pods/ 组件 /Classes 下编码,就是向Development Pods文件夹中添加库文件和资源,将编写的组件相关的class放入YXPlayerSDK/Classes中、资源图片文件放入YXPlayerSDK/Assets中,并配置podspec文件,然后进入Example文件夹执行pod install命令,再打开项目工程可以看到,刚刚添加的组件已经在Pods子工程下Development Pods/YXPlayerSDK中了。
向私有库中添加资源(图片、音视频等)方法共有三种:
第一种
1spec.resources = ["Images/*.png", "Sounds/*"]但是这些资源会在打包的时候直接拷贝的app的Bundle中,这样说不定会和其它资源产生命名冲突
第二种
1spec.resource = "Resources/MYLibrary.bundle"把资源都放在bundle中,然后打包时候这个bundle会直接拷贝进app的mainBundle中。使用的时候在mainBundle中查找这个bundle然后再搜索具体资源
123NSURL *bundleURL = [[NSBundle mainBundle] URLForResource:@"JZShare" withExtension:@"bundle"];NSBundle *bundle = [NSBundle bundleWithURL:bundleURL];UIImage *img = [UIImage imageNamed:icon inBundle:bundle compatibleWithTraitCollection:nil];第三种
1234spec.resource_bundles = {'MyLibrary' => ['Resources/*.png'],'OtherResources' => ['OtherResources/*.png']}这种方法利用 framework 的命名空间,有效防止了资源冲突。pod会把添加的资源文件编译成bundle,使用方法是先拿到最外面的 bundle,然后再去找下面指定名字 的 bundle 对象,再搜索具体资源,其中需要注意的方法 [NSBundle bundleForClass:<#ClassFromPodspec#>] 返回某个 class 对应的 bundle 对象。具体的:
- 如果你的 pod 以 framework 形式被链接,那么返回这个 framework 的 bundle。
- 如果以静态库(
.a
)的形式被链接,那么返回 client target 的 bundle,即 mainBundle。
以下是如何访问:
1234NSBundle *bundle = [NSBundle bundleForClass:[MYSomeClass class]];NSURL *bundleURL = [bundle URLForResource:@"YXPlayerSDK" withExtension:@"bundle"];NSBundle *resourceBundle = [NSBundle bundleWithURL: bundleURL];UIImage *img = [UIImage imageNamed:icon inBundle:bundle compatibleWithTraitCollection:nil];具体分析见 Pod 添加资源文件。
然后提交整个项目代码push到远程分支,并打个tag推送到远程分支,这个tag必须和podspec文件的s.source = { :git => “http://git.jc/elephant-ios-component/YXPlayerSDK.git“, :tag => “0.0.2” }中tag一致。
4、编辑podspec文件
|
|
这里强调一下 s.summary 必填,s.description 不是必填,但如果填写了 s.description,它的长度必须比 s.summary 长且字符串不能一样。
如果要添加更多的模块到YXPlayerSDK之中,包括工具类,底层Model及类目扩展等,就需要subspec功能,给YXPlayerSDK创建了多个子分支。
具体做法是先将源文件添加到YXPlayerSDK/Classes中,然后按照不同的模块对文件目录进行整理,假如我有2个模块,所以在YXPlayerSDK/Classes下会创建了2个子目录,注释podspec文件的s.source_files和s.dependency,修改如下:
|
|
完成后,进入Example文件夹执行pod install命令,会看到目录Development Pods/YXPlayerSDK下多了两个文件夹TestOne和TestTwo,目录结构如下:
|
|
由此创建了subspec所以项目整体的依赖dependency,源文件source_files,头文件public_header_files,资源文件resource等都移动到了各自的subspec中,每个subspec之间也可以有相互的依赖关系(只能单向依赖)如:
这样分为多个subspec,在项目pod就可以使用其中的某个subspec了,如下:
如果已经有了现成的项目,那么就需要给这个项目创建一个podspec文件,创建它需要执行Cocoapods的另外一个命令:
|
|
5、提交pod组件到Spec Repo中
先验证编辑好的podsepc文件,如果因为有无关紧要的警告而未通过检查,则输入以下命令加上--allow-warnings
,如果想要输出编译过程,加上--verbose
:
|
|
如果私有库里面引用静态库会导致验证是无法通过的,报错 include of non-modular header inside framework module ··· [-Werror,-Wnon-modular-include-in-framework-module] ,加上--use-libraries
。
然后还可以本地测试podspec文件,创建一个新的项目,在这个项目的Podfile文件中直接指定刚才创建编辑好的podspec文件,看是否可用, 在Podfile中可以这样编辑:
|
|
编辑完成后,执行pod install命令安装依赖,可以看到YXPlayerSDK跟测试项目一样存在于Development Pods/PodTestLibrary中。
没有自身的WARNING或者ERROR之后,就可以再次提交到Spec Repo中,命令如下:
|
|
之后到~/.cocoapods/repos/JCLiveIOSSpecs目录下查看,也使用pod search命令查看自己库:
这里特别强调一下,如果 s.dependency 中依赖的是 pod 私有库的话,验证和提交命令都需要指定 source :
|
|
6、项目中导入pod私有库组件
当你执行 pod install
的时候,CocoaPods 默认只会在master下搜索,而我们的spec是存在我们私有的JCLiveIOSSpecs目录下的,所以需要在Podfile中指定搜索路径,在文件顶部中如下两行代码:
在指定pod的私有库组件时有一个坑,如pod ‘YXBase’, ‘~> a.b.1’,cocoaPods实际pod组件的版本为a.b.x(x为当前版本库中最大值)。但如何pod指定版本,这就需要修改Podfile.lock文件中PODS:YXBase的版本号和Podfile文件中YXBase版本号一致
7、更新本地cocoapods的spec资源配置信息
pod install 时报错:
|
|
这句话的意思是说:你spec资源中不包含AFNetworking的3.1.0的配置信息。这里面有个关键词,spec资源和配置信息。所以需要更新本地cocoapods的spec资源配置信息,使用命令:
|
|
但pod repo update
实际是更新整个.cocoapods下的所有库,其实我们可以只更新其中某个库来达到快速可用的目的。下面提供两个方法解决:
(1)正规方法:
指定更新单独库pod repo update /Users/<user>/.cocoapods/repos/master/Specs/<lib name>
(2)野路子:
如果方法1仍然无法解决问题,而又着急使用。可以直接到相应目录下手动增加缺少的版本目录和spec文件,/Users/<user>/.cocoapods/repos/master/Specs/<lib name>/3.2.0/<lib name>.spec
。spec文件参考git上相应库的版本。
8、Podfile文件中use_frameworks!
- 在Podfile文件里不使用 use_frameworks! 则是会生成相应的 .a文件(静态链接库),通过 static libraries 这个方式来管理pod的代码。Linked:libPods-xxx.a包含了其它用pod导入的第三方框架的.a文件
在Podfile文件里使用了use_frameworks! 则cocoapods 会生成相应的 .frameworks文件(动态链接库:实际内容为 Header + 动态链接库 + 资源文件),使用 dynamic frameworks 来取代 static libraries 方式。Linked:Pods_xxx.framework包含了其它用pod导入的第三方框架的.framework文件。
用cocoapods 导入swift 框架 到 swift项目和OC项目都必须要 use_frameworks!
使用 dynamic frameworks,必须要在Podfile文件中添加 use_frameworks!
具体分析地址:Podfile中的 use_frameworks!
9、Podfile和target
Podfile本质上是用来描述Xcode工程中的targets用的。如果不显式指定Podfile对应的target,CocoaPods会创建一个名称为default的隐式target,会和工程中的第一个target相对应。换句话说,如果在Podfile中没有指定target,那么只有工程里的第一个target能够使用Podfile中描述的Pods依赖库。
如果想在一个Podfile中同时描述project中的多个target,根据需求的不同,可以有不同的实现方式:
多个target中使用相同的Pods依赖库
1234567link_with 'target1','target2'platform :iospod 'SDWebimage', '~> 1.1.1'platform :ios ,'7.0'pod 'AFNetworking', '~> 2.3.1'不同的target使用完全不同的Pods依赖库
12345678910target :'target1' doplatform :iospod 'SDWebimage', '~> 1.1.1'endtarget :'target2' doplatform :ios ,'7.0'pod 'AFNetworking', '~> 2.3.1'end其中,do/end作为开始和结束标识符。