Cocoapods是 OS X 和 iOS 下的一個第三方庫管理工具。你能使用CocoaPods新增被稱作“Pods”的依賴庫,並輕鬆管理它們的版本,而不用考慮當前的時間和開發環境。
Cocoapods意義體現在兩個方面。首先,引入第三方庫無可避免地要進行各種各樣的配置。對於Objective-C的初級開發者來說,專案配置可是一件艱鉅的任務。在配置編譯階段和連結器選項的過程中,極有可能引入許多人為的錯誤。而CocoaPods簡化了這一切,它能自動配置編譯選項,拯救了開發者。
其次,使用CocoaPods可以很方便地查詢新的第三方庫。當然,這可不是說讓你七拼八湊別人程式碼而開發出一個“移栽”應用。而是讓你找到真正好用的庫,縮短你的開發週期,提升你的程式碼質量。
接下來,我們將通過分析pod安裝的過程,一步步揭示CocoaPods背後的技術。
核心元件
CocoaPods是用ruby寫的,並劃分成了若干個Gem包。CocoaPods在解析執行過程中最重要的幾個包的路徑分別是:CocoaPods/CocoaPods、 CocoaPods/Core 和 CocoaPods/Xcodeproj。
CocoaPods / CocoaPod
這是面向使用者的元件,每當你執行一個pod命令時,這個元件將被啟用。它包括了所有實用CocoaPods的功能,並且還能呼叫其他gem包來執行任務。
CocoaPods / Core
Core gem提供了與CocoaPods相關的檔案(主要是Podfile和podspecs)的處理。
Podfile
Podfile用於配置專案所需要的第三方庫。它能被高度定製,所以你可以儘可能地給它新增你想要的特性。如果您還想對Podfile瞭解更多的話,請檢視Podfile指南(地址 http://guides.cocoapods.org/syntax/podfile.html)。
Podspec
.podspec檔案描述了一個庫將怎樣被新增進工程中。.podspec檔案可以標識該第三方庫所需要的原始碼檔案、依賴庫、編譯選項,以及其他第三方庫需要的配置。
CocoaPods / Xcodeproj
這個包負責工程檔案直接關係的處理。它能建立以及修改.xcodeproj檔案和.xcworkspace檔案。它也可以作為一個獨立的包使用,當你要編寫修改專案檔案的指令碼時,可以考慮使用CocoaPods/Xcodeproj。
執行 pod install 命令
pod install的執行引發了很多操作。瞭解底層執行過程最簡單的方式就是給pod install語句新增 –verbose 引數。現在,執行
1 |
pod install --verbose |
將會出現以下執行結果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
Analyzing dependencies Updating spec repositories Updating spec repo `master` $ /usr/bin/git pull Already up-to-date. Finding Podfile changes - AFNetworking - HockeySDK Resolving dependencies of `Podfile` Resolving dependencies for target `Pods' (iOS 6.0) - AFNetworking (= 1.2.1) - SDWebImage (= 3.2) - SDWebImage/Core Comparing resolved specification to the sandbox manifest - AFNetworking - HockeySDK Downloading dependencies -> Using AFNetworking (1.2.1) -> Using HockeySDK (3.0.0) - Running pre install hooks - HockeySDK Generating Pods project - Creating Pods project - Adding source files to Pods project - Adding frameworks to Pods project - Adding libraries to Pods project - Adding resources to Pods project - Linking headers - Installing libraries - Installing target `Pods-AFNetworking` iOS 6.0 - Adding Build files - Adding resource bundles to Pods project - Generating public xcconfig file at `Pods/Pods-AFNetworking.xcconfig` - Generating private xcconfig file at `Pods/Pods-AFNetworking-Private.xcconfig` - Generating prefix header at `Pods/Pods-AFNetworking-prefix.pch` - Generating dummy source file at `Pods/Pods-AFNetworking-dummy.m` - Installing target `Pods-HockeySDK` iOS 6.0 - Adding Build files - Adding resource bundles to Pods project - Generating public xcconfig file at `Pods/Pods-HockeySDK.xcconfig` - Generating private xcconfig file at `Pods/Pods-HockeySDK-Private.xcconfig` - Generating prefix header at `Pods/Pods-HockeySDK-prefix.pch` - Generating dummy source file at `Pods/Pods-HockeySDK-dummy.m` - Installing target `Pods` iOS 6.0 - Generating xcconfig file at `Pods/Pods.xcconfig` - Generating target environment header at `Pods/Pods-environment.h` - Generating copy resources script at `Pods/Pods-resources.sh` - Generating acknowledgements at `Pods/Pods-acknowledgements.plist` - Generating acknowledgements at `Pods/Pods-acknowledgements.markdown` - Generating dummy source file at `Pods/Pods-dummy.m` - Running post install hooks - Writing Xcode project file to `Pods/Pods.xcodeproj` - Writing Lockfile in `Podfile.lock` - Writing Manifest in `Pods/Manifest.lock` Integrating client project |
整個過程中執行了很多操作,不過把它們分解之後,會發現它們都很簡單。讓我們逐步來分析。
閱讀Podfile檔案
你是否吐槽過Podfile的語法太過詭異,其實這是ruby的語法而不是OC。相較而言,Podfile要比現有的其他格式更加簡單好用一些。
安裝的第一步是要弄清楚哪些第三方庫被顯式或隱式地宣告瞭。CocoaPods載入podspecs檔案時,獲取了第三方庫的名稱及版本列表。Podsspecs檔案儲存在本地,路徑為~/.cocoapods。
版本控制和衝突
CocoaPods使用語義版本命名約定來解決對版本的依賴。由於衝突解決系統建立在非重大更改的補丁版本之間,這使得解決依賴關係要容易得多。舉個栗子,兩個完全不同的第三方庫同時依賴CocoaLumberjack。它們其中一個依賴的版本是2.3.1,而另一個則為2.3.3,解析器可以自動使用較新的版本,在這裡則是2.3.3,因為這可以與2.3.1向後相容。
但這並不總是有效。有許多第三方庫還並不支援這個約定,這讓解決方案變得非常複雜。
當然,總是會有一些衝突需要手工解決。如果一個第三方庫依賴CocoaLumberjack 1.2.5,而另一個依賴CocoaLumberjack 2.3.1,最後只能靠呼叫這兩個第三方庫的使用者來手動地決定CocoaLumberjack的版本了。
載入原始碼
CocoaPods執行的下一個步驟是載入原始碼。每個.podspec檔案都包含了原始碼的索引,這些索引一般指向了一個git地址或者git tag。它們以commit SHA碼的方式儲存在 ~/Library/Caches/CocoaPods中。而在這些路徑中建立檔案則由 Core 包負責。
原始碼將依照Podfile、.podspec和快取檔案的資訊下載到相應的第三方庫路徑。
生成Pods.xcodeproj
每次pod install 執行後並且檢測到改動時,Pods.xcodeproj檔案將唄Xcodeproj gem更新。如果Pods.xcodeproj檔案不存在,則會以預設配置生成,若已存在,則Pods.xcodeproj會使用現有的配置。
安裝第三方庫
當Cocoapods向專案中增加了一個第三方庫的時候,不僅僅是將新增程式碼這麼簡單。由於每個第三方庫有不同的target,所以每次新增第三方庫時,都只有幾個檔案被新增。每個原始碼都需要:
- 一個包含編譯選項的.xcconfig檔案
- 一個同時擁有編譯設定和CocoaPods預設配置的私有.xcconfig檔案
- 編譯所必須的prefix.pch檔案
- 另一個編譯必須的檔案dummy.m
一旦每個pod的target都完成了以上步驟,整個Pods的Target就會被建立。這增加了相同的檔案,與另外幾個。如果有原始碼中包含了資源bundle,向app的target中新增bundle的方式將寫入Pods-Resources.sh。還有一個叫Pods-environment.h的檔案,檔案中含有許多檢查元件是否來自pod的巨集定義。最後,將生成兩個確認檔案,一個.plist檔案,一個用於給使用者查閱許可資訊的markdown檔案。
寫入到磁碟
直到現在,許多已完成的過程都使用的是記憶體中的物件。為了讓這些過程的結果可重複被使用,我們需要將所有結果都記錄在一個檔案中。所以Pods.xcodeproj和另外兩個非常重要的檔案:Podfile.lock和Manifest.lock都將被寫入磁碟。
Podfile.lock
這是CocoaPods建立的最重要的檔案之一。它記錄了需要被安裝的pod的每個已安裝的版本。如果你想知道已安裝的pod是哪個版本,可以檢視這個檔案。推薦將Podfile.lock檔案加入到版本控制中,這有助於整個團隊的一致性。
Manifest.lock
這是每次執行pod install時建立的Podfile.lock檔案的副本。如果你見過“沙盒檔案和Podfile.lock檔案不同步”的錯誤,這個錯誤就是因Manifest.lock檔案和Podfile.lock檔案不一樣引起。由於Pods所在的目錄並不總在版本控制之下,這樣可以保證開發者執行app之前都能更新他們的pods,否則app可能會crash,或者在一些不太明顯的地方編譯失敗
xcproj
如果您已經依照我們的建議在系統上安裝了xcproj,它會將您的Pods.xcodeproj檔案轉換成就舊有ASCII格式的plist檔案。為什麼要這麼做呢?因為Xcode所依賴和使用的plist在很久以前就已經不被其他軟體支援了。如果沒有xcproj,你的Pods.xcodeproj檔案將會以XML格式的plist檔案儲存,當你用Xcode開啟它時,它會被改寫,造成大量的檔案衝突。
執行結果
執行pod install的最終結果是許多檔案被新增到你的工程和系統中。這個過程通常只需要幾秒鐘。當然沒有Cocoapods這些事也都可以完成。只不過所花的時間就不僅僅是幾秒而已了。
旁註:持續整合
CocoaPods和持續整合在一起非常融洽。雖然持續整合很大程度上取決於你的專案配置,但Cocoapods依然能很容易地對專案進行編譯。
Pods資料夾已加入版本控制的持續整合
如果包括Pods資料夾的一切東西都在版本控制之中,那麼你不需要特別做什麼就能夠持續整合。由於編譯時必須指定一個scheme,所以只需要保證使用了正確的scheme即可。
沒有Pods資料夾的持續整合
如果你的Pods資料夾沒有被納入版本控制之中,那麼你需要一些額外的步驟來保證持續整合的順利進行。最起碼,Podfile檔案要放入版本控制之中。另外強烈建議將生成的.xcworkspace檔案和Podfile.lock檔案納入版本控制,這樣不僅簡單方便,更能保證所使用的Pod是正確的版本。
一旦配置完畢,讓CocoaPods在CI上正確執行的關鍵是保證每次編譯之前都執行了pod install。在大多數系統中,譬如Jenkins或者Travis,你只用把“pod install”定義為一個編譯步驟即可(實際上,Travis會自動執行pod install)。隨著Xcode Bot的釋出,我們還沒有找到能像書寫的這麼流暢的解決方案,不過我們正朝著解決方案努力,一旦成功,我們將會立即分享。
結束語
CocoaPods簡化了OC的開發流程,我們的目標是讓第三方庫更容易被發現和新增。瞭解CocoaPods的原理能讓你做出更好的App。我們沿著CocoaPods的整個流程一步步執行,從載入specs檔案和原始碼、建立.xcodeproj檔案和所有元件到將所有檔案寫入磁碟。所以接下來,我們執行 pod install –verbose,靜靜觀察CocoaPods的魔力如何顯現。
(譯註:這是我翻譯的第一篇文章,翻的不好,請各位輕拍。T T )