Cocoapods的原理
pod repo
通过Podfile文件执行pod install
或者pod update
往iOS项目中导入第三方库,实际上是找到podspec
文件中描述的git仓库(svn), 然后从git仓库clone到本地的。
我们从gem安装cocoapods成功之后,在本地的~/.cocoapods/repo
目下的master文件夹下就存在了cocoapods远程仓库的所有索引,也就是spec文件。
通过一层层的查找可以找到与我们需要的第三方库名字一致的一个文件夹,但是文件夹里并没有我们所需的代码文件。
首先repo/master
为什么这么分层呢?
- 这是因为为了合理的对cocoapods数以万计的三方库索引,所以将三方库的名字进行了md5加密然后取前三个字母作为这个第三方库的前三个索引,这样每个目录下存放的库就不会太多,从而减少查找时间。
为什么不是代码文件?
- 因为cocoapods本身就不保存代码文件,它只保留一个库的描述,通过这个库的描述去git仓库去查找代码文件。
pod repo中的文件夹
使用git作为远程仓库push到cocoapods的情况下,git tag
将作为这次push的版本号,这就是为什么repo/master
下的第三方库文件夹中会有一些这样的文件夹。
每个版本对应的文件夹下有一个podspec
文件,这个文件是库的描述:
SDWebImage(4.4.6)的podspec
。
{
"name": "SDWebImage", 名字
"version": "4.4.6", 版本号
"platforms": { 支持的平台
"osx": "10.9",
"ios": "7.0",
"tvos": "9.0",
"watchos": "2.0"
},
"license": "MIT", 开源协议
"summary": "Asynchronous image downloader with cache support with an UIImageView category.", 简述
"homepage": "https://github.com/SDWebImage/SDWebImage", 主页
"authors": { 作者
"Olivier Poitrey": "rs@dailymotion.com"
},
"source": { 源文件仓库
"git": "https://github.com/SDWebImage/SDWebImage.git",
"tag": "4.4.6"
},
"description": "This library provides a category for UIImageView with support for remote images coming from the web. It provides an UIImageView category adding web image and cache management to the Cocoa Touch framework, an asynchronous image downloader, an asynchronous memory + disk image caching with automatic cache expiration handling, a guarantee that the same URL won't be downloaded several times, a guarantee that bogus URLs won't be retried again and again, and performances!", 描述
"requires_arc": true, 是否是在ARC下
"frameworks": "ImageIO", 需要的framework
"default_subspecs": "Core", 默认的子库 有多个子库的情况下
"subspecs": [ 子库 每个子库可以作为一个独立的库引入到项目中
{
"name": "Core", 名字
"source_files": "SDWebImage/{NS,SD,UI}*.{h,m}", 文件路径 通过通配符查找
"exclude_files": [ 不包含的文件
"SDWebImage/UIImage+WebP.{h,m}",
"SDWebImage/SDWebImageWebPCoder.{h,m}"
],
"tvos": { tvos平台下的配置
"exclude_files": "SDWebImage/MKAnnotationView+WebCache.*"
}
},
{
"name": "MapKit",
"platforms": {
"osx": "10.9",
"ios": "7.0",
"tvos": "9.0"
},
"source_files": "SDWebImage/MKAnnotationView+WebCache.*",
"frameworks": "MapKit",
"dependencies": { 依赖的库
"SDWebImage/Core": [
]
}
},
{
"name": "GIF",
"platforms": {
"ios": "7.0"
},
"source_files": "SDWebImage/FLAnimatedImage/*.{h,m}",
"dependencies": {
"SDWebImage/Core": [
],
"FLAnimatedImage": [
"~> 1.0"
]
}
},
{
"name": "WebP",
"source_files": [
"SDWebImage/UIImage+WebP.{h,m}",
"SDWebImage/SDWebImageWebPCoder.{h,m}"
],
"xcconfig": { xcode的配置
"GCC_PREPROCESSOR_DEFINITIONS": "$(inherited) SD_WEBP=1",
"USER_HEADER_SEARCH_PATHS": "$(inherited) $(SRCROOT)/libwebp/src"
},
"watchos": {
"xcconfig": {
"GCC_PREPROCESSOR_DEFINITIONS": "$(inherited) SD_WEBP=1 WEBP_USE_INTRINSICS=1",
"USER_HEADER_SEARCH_PATHS": "$(inherited) $(SRCROOT)/libwebp/src"
}
},
"dependencies": {
"SDWebImage/Core": [
],
"libwebp": [
">= 0.5"
]
}
}
]
}
创建一个私有cocoapods仓库
创建存放podsepc的仓库
通过上述原理,如果创建一个私有的cocoapods仓库就不能将仓库的podspec
文件发布到cocoapods的repo中。
所以我们需要在自己的git服务器中创建一个保存podspec
的仓库。最好保证仓库创建的时候是一个空仓库,不需要使用readme之类的文件去初始化它。否则会有git冲突的情况需要解决。
创建完仓库之后获取仓库地址 在terminal中执行pod的指令将仓库添加到本地的pod repo中。
pod repo add [name] [url]
添加完成之后再~/.cocoapods/repo
中就可以看到和master同级的一个目录,也就是存放库索引的地方。
当然也可以使用pod repo remove [name]
移除repo。
创建存放源码的仓库并推送到私有cocoapods
在git服务器上再创建一个仓库用于存放源代码。
在terminal中执行pod lib create 名字
创建一个cocoapods的demo文件。
pod lib create test
Cloning `https://github.com/CocoaPods/pod-template.git` into `test`.
Configuring test template.
security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.
------------------------------
To get you started we need to ask a few questions, this should only take a minute.
If this is your first time we recommend running through with the guide:
- https://guides.cocoapods.org/making/using-pod-lib-create.html
( hold cmd and click links to open in a browser. )
What platform do you want to use?? [ iOS / macOS ]
> ios
What language do you want to use?? [ Swift / ObjC ]
> objc
Would you like to include a demo application with your library? [ Yes / No ]
> yes
Which testing frameworks will you use? [ Specta / Kiwi / None ]
> none
Would you like to do view based testing? [ Yes / No ]
> no
What is your class prefix?
> soc
执行之后会从git克隆一个模板,并会问几个问题,依次按照需求选择即可。完成之后会打开一个Xcode project。
在上图的路径(也就是replaceme.m存放的目录)下添加文件并删除replaceme.m
。
进入Example目录 配置Podfile,将项目名称.podspec
配置到Podfile中,如果有依赖库,顺便添加。
platform :ios, '8.0'
target 'SoCNetWork_Example' do
pod 'SoCNetWork', :path => '../SoCNetWork.podspec'
pod 'AFNetworking' # 依赖AFNetworking
pod 'YYCache' # 依赖YYCache
end
保存之后执行 pod update
(可选参数:--verbose 可以查看详细的过程 | --no-repo-update 不升级本地的repo会快一些)
执行结束之后在Pods
的Development Pods
目录下就可以看到我们添加的文件了。
另外依赖的AFNetworking
和YYCache
也添加到项目中了。
编译一下有错改之,无错进行下一步。
编辑podspec文件
Pod::Spec.new do |s|
s.name = '名字'
s.version = '版本号 需要和git tag保持一致'
s.summary = '简述'
# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
# * Try to keep it short, snappy and to the point.
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = <<-DESC
TODO: 描述
DESC
s.homepage = '主页 最好保证可以访问'
s.license = { :type => 'MIT', :file => 'LICENSE' } #开源协议
s.author = { 'SoC' => 'joeqq1028@163.com' } #作者
s.source = { :git => 'git仓库地址', :tag => s.version.to_s }
s.ios.deployment_target = '8.0' #最低支持的系统版本
s.source_files = 'SoCNetWorkOAuth1.0/Classes/**/*' #文件路径
s.dependency 'AFNetworking' #依赖的库
s.dependency 'YYCache' #依赖的库
end
关于source_files
这里如果添加的目录有嵌套可以使用subspec来实现。
例如:
OAuth1.0下面有一个oauthcore文件夹。
podspec
的source_file
项的填写,不再需要s.source_file
可以使用如下示例填写:
s.subspec 'OAuth1.0' do |ss|
ss.source_files = '项目名/Classes/OAuth1.0/*.{h,m}'
ss.subspec 'oauthcore' do |sss|
sss.source_files = '项目名/Classes/OAuth1.0/oauthcore/*.{h,m}'
end
end
关于搜索文件的通配符在cocoapods官网中已经描述的很清楚了
创建完成之后使用pod lib lint
来验证podspec填写的准确性。可以选择参数:
- --verbose 查看整个过程
- --allow-warnings 允许一些警告通过验证 `如果验证出错,而project build success 可以尝试添加这个参数
- --source 如果依赖的库是一个私有仓库创建的库,可以使用这个参数指定私有仓库的podspec仓库,除此之外最好将cocoapods公有库的source也指定一下.比如(
pod lib lint --sources='[私有podsepec仓库地址],https://github.com/CocoaPods/Specs' --verbose --allow-warnings --no-clean
)
验证通过之后 需要将文件push到git仓库中:
git init
git add .
git commit -am 'desc'
git remote add origin 'url'
git push origin master
git tag 'tag'
git push --tags
添加完成之后将podsepc添加到私有repo中使用命令
pod repo push [repo name] [name.podspec] --verbose --allow-warnings
可选参数同样包括上述的--source=
,跟上面描述的一样,不再赘述。
这样创建私有库的工作就完成了。
使用私有cocoapods仓库
使用私有仓库的时候需要在Podfile
中指定source。
source 'repo git url' # 私有仓库(存放podsepc文件的仓库)git地址
source 'https://github.com/CocoaPods/Specs.git' # cocoapods 公用仓库地址
platform :ios, '8.0'
target 'CTVITNetWork' do
pod 'name'
end
当遇到使用依赖库创建子类的时候会在 .h 文件中引入依赖库的头文件 而这样通常会在 执行 pod repo push
的时候发生错误。这个时候在 pod repo push
命令中添加 --use-libraries
参数可解决这个问题。而如果 .h 文件对依赖库中类的引用是非必须的, 也可以将 依赖库中类的声明放到 .m 中, 以解决这个错误。