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 中, 以解決這個錯誤。