理解Cocoapods

對於作 iOS 開發的朋友來講,Cocoapods 是一件沒必要可少的得利工具,它是一個管理第三方庫,而且解決其依賴關係的工具,可是有不少朋友對其運做的機制知其然殊不知其因此然。筆者就在這裏簡單的講解一下。ios

新石器時代

對於任何一項編程來講,早期未造成工程化的時候,是不存在所謂依賴管理的概念的,iOS 也是同樣,早期 iOS 開發若是想要使用第三方庫,是很是繁瑣的一件事情。git

  1. 將第三方庫源代碼複製到工程目錄,或者使用 git submodule 將其做爲項目的一個模塊編程

  2. 設置工程文件,添加第三方庫依賴的系統庫xcode

  3. 對於某些第三方庫,可能須要設置一些編譯選項( etc. -fno-objc-arc架構

  4. 最後就是管理第三方庫代碼的更新工具

這些都是體力活,爲了能省去這些工做,有沒有辦法呢?
答案是有的,iOS 開發終究仍是很傳統的 Unix 開發,直接把第三方庫源代碼抽離出來,打包成靜態庫就好了(PS:在 iOS 8 以前蘋果只容許使用靜態庫,而 iOS 8 後就能夠打包動態庫了,固然,其實是同樣的。)。這樣的話就不須要擔憂過多的源代碼導入的繁瑣,也不須要擔憂第三方庫究竟需不須要編譯選項,並且第三方庫更新只須要更新靜態庫就好了。簡直是美好的人生。ui

農耕時代

封裝成靜態庫或動態庫看起來確實美好了,方便快捷,這也是 Unix 下的解決方案。可是隻要仔細一想,問題一大堆。spa

  1. 某些第三方庫極可能直接依賴另外一項第三方庫,依賴若是使用手工解決將會是很大的工做。版本控制

  2. 動態庫不能用於 iOS 7 及如下版本code

  3. 工程依舊須要設置依賴的系統庫

  4. 仍然須要手工更新第三方庫版本

對於 Unix 環境來講,動態庫能夠存放在系統默認搜索路徑下,這樣全部的應用均可以共享同一個內存副本,並且升級動態庫的時候能夠一塊兒升級,不須要到各處尋找。可是 iOS 的動態庫其實是縮水的,由於蘋果將動態庫限制在了沙盒內部,其餘 App 徹底不能訪問此動態庫。這就限制了動態庫的優勢。還有一點緣由就是指令集架構的不一樣,iOS 模擬器使用的是 x86 架構指令集,而真機則是 ARM64 等指令集,若是想要方便使用,最好須要打包通用架構的靜態庫,可是這是很繁瑣的工做。
因爲以上緣由,手工封裝靜態庫或者動態庫實際上在項目小的時候是能夠的,可是項目規模一旦擴大就會致使效率低下。

工業時代

爲了可以自動化流水做業,就引出了依賴包管理的概念,也就是 Cocoapods。Cocoapods 本質上仍是上面所說的封裝動態庫靜態庫,可是它解決的最大問題就是依賴管理。開發者不須要從 Github 的地方辛苦的尋找代碼,只須要一條命令,就能下載整合第三方庫。這些優勢都沒必要說,筆者下面就具體講解 Cocoapods 到底對咱們的工程作了什麼事情。
首先使用 Xcode 建立了一個工程,使用 git init 命令將其歸入版本控制,作第一次提交。而後寫 Podfile,直接跟隨 Cocoapods 官網文檔寫最簡單的內容。

使用 framework

platform :ios, '8.0'
use_frameworks!

target 'test' do
  pod 'AFNetworking', '~> 2.6'
end

而後輸入如下命令整合第三方庫。

> pod install

如今能夠看一下修改的內容。

> git status

On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   test.xcodeproj/project.pbxproj

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    Podfile.lock
    Pods/
    test.xcworkspace/

因爲輸出過場,這裏就不貼 git diff 命令的輸出了,從 git diff 命令輸出能夠看出,主要修改了 .xcodeproj/project.pbxproj 文件的內容,而且將原先的文件格式轉化爲了 XML 文件格式。而且,能夠看出來,添加了一個 工程名.xcworkspace 的工做空間,將原先的工程文件和新的 Pods 工程放到了同一個工做空間下。

<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "group:test.xcodeproj">
   </FileRef>
   <FileRef
      location = "group:Pods/Pods.xcodeproj">
   </FileRef>
</Workspace>

很顯然,全部的配置都被放到了工程文件中,工做空間實際上只是一個工程的整合。
因爲文件格式不一樣,沒法很好的對比反映工程文件到底哪裏被修改了,可是從實際的工程打開後觀察,也能稍微瞭解。總結以下:

  1. 在 General -> Linked Frameworks and Libraries 中添加了 Pods_test.framework 的依賴

  2. Build Settings -> Other Linker Flags 中添加了 -framework "AFNetworking"

  3. Build Settings -> RunPath Search Paths 中添加了 @executable_path/Frameworks

  4. Build Settings -> Other C Flags 添加 -iquote "$CONFIGURATION_BUILD_DIR/AFNetworking.framework/Headers" 和 Other C++ Flags 添加 $(OTHER_CFLAGS),也就是說,跟隨 Other C Flags 配置

  5. Build Settings -> Preprocessor Macros 添加 COCOAPODS=1

  6. Build Settings -> User-Defined -> MTL_ENABLE_DEBUG_INFO PODS_FRAMEWORK_BUILD_PATH PODS_ROOT 三個變量

  7. Build Phases -> Embed Pods Frameworks 添加 "${SRCROOT}/Pods/Target Support Files/Pods-test/Pods-test-frameworks.sh"

  8. Build Phases -> Copy Pods Resources 添加 "${SRCROOT}/Pods/Target Support Files/Pods-test/Pods-test-resources.sh"

從上面能夠看出,若是在 Podfile 中指定了 use_frameworks! 則會使用動態庫封裝其內容,而上面所作的主要工做就是添加對另外一個工程的依賴,添加連接器選項使其連接 framework,將動態庫運行時搜索路徑設置爲 @executable_path/Frameworks 也就是說 ${BUNDLE_ROOT}/Frameworks,設置 C 和 C++ 編譯器的頭文件搜索路徑,將 framework 放置到沙盒目錄
而後再來看 Pods 工程,Pods 工程將每一個第三方庫都使用一個 target 表示,還有一個 target 則是用於生成主要的庫文件,須要注意的是,雖然第三方庫的 target 生成的是動態庫,可是最終的 target 生成的是靜態庫,可是隻是起一個集合的做用,實際的二進制代碼仍是被存放在各個動態庫中,其主要修改了 Build Settings 內容

  1. 將 framework 的輸出路徑指定爲 ${SRCROOT}/../build

  2. 指定 iOS Deployment Target 爲原先 Podfile 中指定的版本,這是一個容易被人忽視的地方,不少朋友都覺得 Podfile 中 platform 指令指定的是主工程的 deployment target,其實是指定 Pods 工程的每一個 target

主要就是這兩點,其餘都是一些細碎的細節,好比將輸出類型指定爲動態庫,設置第三方庫依賴。
而後就是 Pods-工程名-frameworks.shPods-工程名-resources.sh,這兩個文件實際上就是將封裝通用架構動態庫文件和將動態庫複製到 bundle 指定目錄下。有興趣的朋友能夠仔細看看。

不使用 framework

framework 只能在 iOS 8 以上平臺使用,可是大多數狀況下,工程都是須要兼容 iOS 7 版本的,因此 framework 功能只能捨棄掉,由於目前兼容版本都是以 UI 特徵來劃分兼容版本,iOS 6 及之前版本都算擬物化 UI,而 iOS 7 及之後版本則是扁平化風格。
這裏先將 Podfile 中的 use_frameworks! 刪除掉,再 pod install
經過 git diff 命令能夠看到,實際上兩種方式差異不大,只是不使用動態庫而是使用靜態庫替代了全部的動態庫,而後在 Other Linker Flags 中添加了 -ObjC和連接器命令連接所依賴的系統 framework,原先則是在 Pods 工程具體的 target 中才存在連接器命令連接系統 framework。並且還發現,在 Header Search Path 中添加了頭文件的搜索路徑。

後記

Cocoapods 雖然侵入性很強,可是對於新手來講,屏蔽了不少底層的操做,很是便於實踐,對於重複的工做也獲得了很好的替代,若是有朋友想要補充,能夠在下方留言指正。

相關文章
相關標籤/搜索