使用CocoaPods创建自己的私有库,既可以将自己的私有库简单方便的提供给其他开发者使用,又可以安全方便的对自己的私有库进行维护升级;同时创建CocoaPods私有库也是组件化开发的第一步,随着越来越多的开发者使用CocoaPods技术进行开发管理,所以学会创建CocoaPods私有库将是一个开发者必会的开发技巧。
一、理解 spec repository
和 code repository
远程仓库
- code repository :是指
代码
仓库;通常把组件库的代码上传到这个仓库里。 - spec repository :是指
Pod配置
仓库;所有的配置按照组件名、版本号分门别类的存放在这个仓库,多个组件可共用一个Pod配置
仓库。
注意:spec repository
库只用来存放spec
文件,不存放代码。
二、创建 spec repository
和 code repository
远程仓库
可以去github
、gitee
等代码托管平台创建远程仓库,本文以gitee
创建远程仓库为例。
2.1 创建spec repository
索引远程仓库
2.2 创建code repository
代码远程仓库
三、创建本地spec库
并关联远程spec库
3.1 查看本地已存在的索引库
$ pod repo
3.2 添加本地私有索引库并与远程私有库
//$ pod repo add LibrarySpec https://gitee.com/skylands/LibrarySpec.git
$ pod repo add 本地文件名 sourceURL
3.3 关联后再次查看本地已存在的索引库
四、创建组件测试工程
4.1 打开iTerm
切换到目标路径
$ cd 预先准备存储仓库代码的目录
4.2 执行创建组件工程的命令
$ pod lib create GMLFMBase
在iTerm
中填写组件工程的配置信息,如下图:
4.3 添加组件的相关代码
打开创建好的组件工程,查看本地的工程目录结构
- 样例工程文件:
Library/Example
- 存放资源文件:
Library/Library/Assets
- 存放组件代码:
Library/Library/Classes
4.4 打开Example
工程目录下的podfile
文件
#pod 'Library', :path => '../' #指定路径
pod 'Library', :path => '../Library.podspec' #指定podspec文件
然后在Example
工程目录下执行pod install
命令安装依赖,再打开工程,可以看到库文件都被加载到Pods/Development Pods/Library
目录中了,如下图:
**4.5 ** 提交代码到组件的代码远程仓库
$ git add .
$ git commit -m "创建Library组件库" #提交修改到本地仓库
$ git remote add origin [git仓库地址] #关联本地仓库与代码远端仓库
$ git pull origin master --allow-unrelated-histories #强制拉取远程代码并合并
# 注意
# 如果存在冲突文件需要先解决冲突再推到远程仓库
# 解决完冲突后 git add . 和 git commit -m"日志" 重新执行一遍
# 再执行 git push origin master 命令推送代码到远程仓库
$ git push origin master #提交到代码远端仓库
到这里,已经成功的创建组件代码工程并提交到远程代码仓库,初步完成了Library
的Pod库
的代码实现部分,接下来只需要将制作的私有库
放到podspec
索引仓库了。
五、提交 podspec 文件到私有 Spec Repo 远程仓库
5.1 配置 podspec
文件
打开Library
工程目录下的Library.podspec
文件并参考下图的说明配置好相关选项。
5.2 验证Library.podspec
文件是否可用
$ cd Example路径下
$ pod lib lint --allow-warnings
如果终端输出这个信息,就说明验证通过;否则会提示错误信息,需要去修改后继续验证可用性。
5.3 验证通过后将Library.podspec
提交到远程代码仓库并打tag
值
$ git add .
$ git commit -m "创建Library组件库" #提交修改到本地仓库
$ git remote add origin [git仓库地址] #关联本地仓库与代码远端仓库
$ git pull origin master #拉取远程仓库代码
$ git push origin master #提交到代码远端仓库
# 注意:这个很重要
# 打上标签并且与podSpec中的tag保持一致
$ git tag -m "first create release" "0.1.1"
$ git push --tags
5.4 将podspec
文件提交到本地的私有索引库
# pod repo push [Repo名] [podspec 文件名字]
$ pod repo push LibrarySpec Library.podspec --allow-warnings
如果提交成功,终端上就会输出一些相关pod
信息,如下图;如果不成功,则会打印一些失败信息,然后去解决对应的问题,再继续此操作,直至提交成功。
六、使用创建好的私有 Spec Repo
库
具体将普通工程支持CocoaPods
管理第三方的工程请参考前一篇文章:CocoaPods工具的安装教程以及简单使用。下面主要说下怎么修改Podfile
文件,从而引入创建好的私有 Spec Repo
库。
- 第一种方法:直接指定某一个依赖的
podspec
库,方便内部的公共项目支持CocoaPods
管理
# 用Xcode找到 Podfile 并打开此文件
pod 'LibrarySpec', :podspec => 'https://gitee.com/skylands/LibrarySpec.git'
- 第二种方法:在
Podfile
文件中添加source
以及pod
命令
七、给组件 Pods
添加资源文件
7.1 访问组件Pods
中的NSBundle
的资源
在 podspec
文件里面,添加resource_bundles
的配置
s.resource_bundles = {
'MyLibrary' => ['your/path/Assets/**/*.{png,xib,plist}']
}
一般情况下,我们自己创建的pods
添加的资源文件,使用[NSBundle mainBundle]
是找不到该资源的路径,所以在这里,我们需要创建NSBundle
的category
分类,新增方法来访问bundle
资源文件。
@implementation NSBundle (MyLibrary)
+ (NSBundle *)my_myLibraryBundle {
return [self bundleWithURL:[self my_myLibraryBundleURL]];
}
+ (NSURL *)my_myLibraryBundleURL {
NSBundle *bundle = [NSBundle bundleForClass:[MYSomeClass class]];
return [bundle URLForResource:@"MyLibrary" withExtension:@"bundle"];
}
@end
MYSomeClass
这个类可以是任意类名,但是有个前提,这个类必须是在你创建的library
或者framework
内。再说这个逻辑:先拿到最外面的bundle
,对framework
链接方式来说是 framework
的bundle
的根目录,对静态库链接方式来说就是target client
的main bundle
,然后再去找下面名为MyLibrary
的bundle
7.2 图片资源的访问
现在可以正常访问当前组件的NSBundle
了,如果访问组件NSBundle
内的图片资源,还是一样的方法,为UIImage
创建一个category
分类,新增方法来访问UIImage
资源文件。
#import "UIImage+MyLibrary.h"
#import "NSBundle+MyLibrary.h"
@implementation UIImage (MyLibrary)
+ (UIImage *)my_bundleImageNamed:(NSString *)name {
return [self my_imageNamed:name inBundle:[NSBundle my_myLibraryBundle]];
}
+ (UIImage *)my_imageNamed:(NSString *)name inBundle:(NSBundle *)bundle {
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
return [UIImage imageNamed:name inBundle:bundle compatibleWithTraitCollection:nil];
#elif __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_8_0
return [UIImage imageWithContentsOfFile:[bundle pathForResource:name ofType:@"png"]];
#else
if ([UIImage respondsToSelector:@selector(imageNamed:inBundle:compatibleWithTraitCollection:)]) {
return [UIImage imageNamed:name inBundle:bundle compatibleWithTraitCollection:nil];
} else {
return [UIImage imageWithContentsOfFile:[bundle pathForResource:name ofType:@"png"]];
}
#endif
}
@end
+ imageNamed:inBundle:compatibleWithTraitCollection:
这个方法iOS8
以后才有,所以需要条件编译。+ imageWithContentsOfFile:
没有缓存机制。
八、创建私有 Spec Repo
库常见的问题
8.1 在创建私有pods
遇到引用第三方framework
(例如umeng
等)
需要注意,如果pod repo push
出现下面的错误信息:
can't get podspec validation - ERROR | [iOS] xcodebuild: Returned an unsuccessful exit code
解决办法,可以试试:
$ pod lib lint --allow-warnings
# 解决所有的warning
$ pod repo push .podspec --allow-warnings --use-libraries
如果pod lib lint --allow-warnings
出现一些not find file
之类的warning
,一定要解决掉,否则也会出现以上错误信息。
8.2 不更新CocoaPods
的pod spec
索引库
CocoaPods
在执行pod install
和pod update
时,会默认先更新一次pod spec
索引,使用--no-repo-update
参数可以禁止其做索引更新操作。
$ pod install --no-repo-update
$ pod update --no-repo-update
8.3 遇到 Unable to find a specification for 'xxxxx'
问题
有时候在安装某一第三方会出现 Unable to find a specification for 'xxxxx'
这个问题,只需要把当前Pod
的目录清理一下就行了。在终端执行以下命令:
$ pod repo remove master
$ pod setup
pod setup
可能需要花费很长时间,成功后执行install
或update
即可。