1. 程式人生 > >objc系列譯文(6.4):深入理解 CocoaPods

objc系列譯文(6.4):深入理解 CocoaPods

Cocoapods是 OS X 和 iOS 下的一個第三方庫管理工具。你能使用CocoaPods新增被稱作“Pods”的依賴庫,並輕鬆管理它們的版本,而不用考慮當前的時間和開發環境。

Cocoapods意義體現在兩個方面。首先,引入第三方庫無可避免地要進行各種各樣的配置。對於Objective-C的初級開發者來說,專案配置可是一件艱鉅的任務。在配置編譯階段和連結器選項的過程中,極有可能引入許多人為的錯誤。而CocoaPods簡化了這一切,它能自動配置編譯選項,拯救了開發者。

其次,使用CocoaPods可以很方便地查詢新的第三方庫。當然,這可不是說讓你七拼八湊別人程式碼而開發出一個“移栽”應用。而是讓你找到真正好用的庫,縮短你的開發週期,提升你的程式碼質量。

接下來,我們將通過分析pod安裝的過程,一步步揭示CocoaPods背後的技術。

核心元件

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 引數。現在,執行

Shell
1 pod install--verbose

將會出現以下執行結果:

Shell
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 Analyzing dependencies Updating spec repositoriesUpdating spec repo`master`$/usr/bin/git pullAlready up-to-date.Finding Podfile changes-AFNetworking-HockeySDKResolving dependencies of`Podfile`Resolving dependencies fortarget`Pods'(iOS6.0)-AFNetworking(=1.2.1)-SDWebImage(=3.2)-SDWebImage/CoreComparing resolved specification tothe sandbox manifest-AFNetworking-HockeySDKDownloading dependencies->Using AFNetworking(1.2.1)->Using HockeySDK(3.0.0)-Running pre install hooks-HockeySDKGenerating Pods project-Creating Pods project-Adding source files toPods project-Adding frameworks toPods project-Adding libraries toPods project-Adding resources toPods project-Linking headers-Installing libraries-Installing target`Pods-AFNetworking`iOS6.0-Adding Build files-Adding resource bundles toPods project-Generating public xcconfig fileat`Pods/Pods-AFNetworking.xcconfig`-Generating private xcconfig fileat`Pods/Pods-AFNetworking-Private.xcconfig`-Generating prefix header at`Pods/Pods-AFNetworking-prefix.pch`-Generating dummy source fileat`Pods/Pods-AFNetworking-dummy.m`-Installing target`Pods-HockeySDK`iOS6.0-Adding Build files-Adding resource bundles toPods project-Generating public xcconfig fileat`Pods/Pods-HockeySDK.xcconfig`-Generating private xcconfig fileat`Pods/Pods-HockeySDK-Private.xcconfig`-Generating prefix header at`Pods/Pods-HockeySDK-prefix.pch`-Generating dummy source fileat`Pods/Pods-HockeySDK-dummy.m`-Installing target`Pods`iOS6.0-Generating xcconfig fileat`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 fileat`Pods/Pods-dummy.m`-Running post install hooks-Writing Xcode project fileto`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 )