1、什么是CocoaPods
CocoaPods 是開發 OS X 和 iOS 應用程序的一個第三方庫的依賴管理工具。利用它可以定義自己的依賴關系 (稱作 pods),并且隨著時間的變化,以及在整個開發環境中對第三方庫的版本管理非常方便。這里整理了從基本安裝到使用的操作流程和期間容易出現的問題以及解決辦法。
2、CocoaPods都做了什么
簡單查看一下cocoapods源代碼(ruby語言),了解一下install和update過程都干了什么。 參考:cocoapods都做了什么
CocoaPods/lib/cocoapods/command/install.rb
def run
verify_podfile_exists!
installer = installer_for_config //Podfile的內容解析
installer.repo_update = repo_update?(:default => false)
installer.update = false //和update的區別
installer.install!
end
CocoaPods/lib/cocoapods/command/update.rb
def run
verify_podfile_exists!
installer = installer_for_config
installer.repo_update = repo_update?(:default => true)
if @pods
verify_lockfile_exists!
verify_pods_are_installed!
installer.update = { :pods => @pods }
else
UI.puts 'Update all pods'.yellow
installer.update = true
end
installer.install!
end
CocoaPods/lib/cocoapods/installer.rb
def install!
prepare
resolve_dependencies //處理依賴關系、比如是根據本地specs文件呢還是遠端git地址等
download_dependencies//跟進依賴關系下載對應依賴包
validate_targets
generate_pods_project //生成pods.xcodeproj工程,將依賴中的文件、Library加入工程,設置target dependencies、生成workspace//
if installation_options.integrate_targets?
integrate_user_project
else
UI.section 'Skipping User Project Integration'
end
perform_post_install_actions
end
總結
Podfile的內容解析
repo的更新檢查
處理Podfile中的依賴關系
下載依賴資源
生成pods.xcodeproj工程
將依賴中的文件、Library加入工程
設置target dependencies
生成workspace
3、CocoaPods的安裝
1.安裝過程
安裝方式異常簡單 , Mac 下都自帶 ruby,使用 ruby 的 gem 命令即可下載安裝:
$ sudo gem install cocoa pods
$ pod setup
2.安裝過程可能出現的錯誤
gem版本需要更新
首先確認軟件源地址是正確的,然后如果你的 gem 太老,可能也會有問題,可以嘗試用如下命令升級 gem。
$ sudo gem update –system //sudo 執行 不然會報無權限錯誤
更新完成 gem 后 :
$ gem update cocoapod //更新cocoapod
$ pod setup pod //更新完成后初始化
$ pod repo update —verbose //更新repo
如果報錯,先移除原來的緩存文件:
$ rm -rf ~/.cocoapods/repos/master //然后再 pod setup。
pod setup 卡住在 Setting up CocoaPods master repo
這步其實是 Cocoapods 在將它的信息下載到 ~/.cocoapods 目錄下,如果你等太久,可以試著 cd 到那個目錄,用 du -sh * 來查看下載進度。
如果還是慢,更新一下軟件源:
ruby 的軟件源 https://rubygems.org
因為使用的是亞馬遜的云服務,所以被墻了,需要更新一下 ruby 的源。并且由于淘寶源已經不再進行更新維護,改成由 ruby-china 管理維護 所以源改成 https://gems.ruby-china.org/
。
gem sources –remove https://rubygems.org // 移除默認源
gem sources -a https://gems.ruby-china.org // 添加新的源
gem sources -l //查看sources源 看是否已經更換
4、CocoaPods基礎應用
1.項目中的使用方法
使用時需要新建一個名為 Podfile 的文件,以如下格式,將依賴的庫名字依次列在文件中即可:
source 'https://github.com/CocoaPods/Specs.git' //可以在這里按這種格式配置其他倉庫
target 'MyApp' do
platform :ios, '6.0' //IOS 系統、版本要求
pod 'MJExtension', '~> 2.5.12' //引入的pod項目對應的項目名稱 和版本號
platform :ios,'7.0'
pod 'FMDB','~> 2.6.0'//~>符號指的是 2.6 級別版本獲取最新的版本'
end
然后你將編輯好的 Podfile 文件放到你的項目根目錄中,執行如下命令即可:
cd “你的podfile所在目錄”
pod install
現在,你的所有第三方庫都已經下載完成并且設置好了編譯參數和依賴,你只需要記住如下:
使用 CocoaPods 生成的 .xcworkspace 文件來打開工程,而不是以前的 .xcodeproj 文件。
每次更改了 Podfile 文件,你需要重新執行一次 pod update 命令。
當不知道某款第三方庫的引入方法時可以直接在終端查找第三方庫 或者 你如果不知道 CocoaPods 管理的庫中,是否有你想要的庫,那么你可以通過 pod search xxx 命令進行查找
2.CocoaPods使用中的tips
1.關于 Podfile.lock
當你執行 pod install 之后,除了 Podfile 外,CocoaPods 還會生成一個名為 Podfile.lock 的文件,Podfile.lock 應該加入到版本控制里面,不應該把這個文件加入到 .gitignore 中。
因為 Podfile.lock 會鎖定當前各依賴庫的版本,之后如果多次執行 pod install 不會更改版本,要pod update 才會改 Podfile.lock 了。
這樣多人協作的時候,可以防止第三方庫升級時造成大家各自的第三方庫版本不一致。
后面的CocoaPods私人倉庫創建會講到 podspec 文件的問題
2.–-no-repo-update
CocoaPods 在執行 pod install 和 pod update 時,會默認先更新一次 podspec 索引,會去更新 repo。
使用 --no-repo-update 參數可以禁止其做索引更新操作。如下所示:
pod install –-no-repo-update
pod update –-no-repo-update
3.移除tag0.0.1,再重現提交新的tag0.0.1
git add .
git commit -m"cover tag 0.0.1"
git push
git tag -d 0.0.1
git push origin :refs/tags/0.0.1
git tag 0.0.1
git push origin 0.0.1
4.CocoaPods原理
大概研究了一下 CocoaPods 的原理,它是將所有的依賴庫都放到另一個名為 Pods 項目中,然后讓主項目依賴 Pods 項目,這樣,源碼管理工作都從主項目移到了 Pods 項目中。發現的一些技術細節有:
1.Pods 項目最終會編譯成一個名為 libPods.a 的文件,主項目只需要依賴這個 .a 文件即可。
2.對于資源文件,CocoaPods 提供了一個名為 Pods-resources.sh 的 bash 腳本,該腳本在每次項目編譯的時候都會執行,將第三方庫的各種資源文件復制到目標目錄中。
3.CocoaPods 通過一個名為 Pods.xcconfig 的文件來在編譯時設置所有的依賴和參數。
3.創建私有倉庫
使用pod的時候 我們會遇到需要將自己的代碼封裝出去 單獨管理的情況,這種情況下 我們就需要一個私有的倉庫來管理這些單獨的部件。
1.創建一個支持pod引入的項目
cocoapods提供了一個快捷的項目模板創建命令:
$ pod lib create 你要創建的項目的項目名稱
執行命令會有如下選擇過程:
//pod lib create 你要創建的項目的項目名稱 命令執行后會詢問基本信息
//1.是否需要一個例子工程;2.選擇一個測試框架;3.是否基于View測試;4.類的前綴;
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?
> YG
依次按需要執行完成就會生成一個有格式的項目。
生成項目分為 Example 和 Pods 兩個主要的目錄。
Pods
|- Assets 文件夾,//用來存放本地資源,比如圖片、Assets.xcassets等
|- Classes 文件夾,//存放pod的.m.h.swift.xib文件等
|
Example 文件夾,//就是一個demo項目方便pod代碼開發
| |- demoProject.xcodeproj
| |- demoProject.xcworkspace
| |- Podfile //就是一個demoPod項目的 第三方庫依賴描述文件
| |- Podfile.lock
| |- demoProject
| |- Pods //其他第三方庫依賴描述文件存放文件夾
| |- Tests
LICENSE //開源協議文件
|
demoProject.podspec //這個pod文件的說明書,下面會詳細說
項目在xcode中的結構如下:
其中重要的兩個部分是 *.podspec 文件 和 pods下面的 Development Pods 目錄其實就是上面提到的Pod目錄。.podspec 就像一個說明書,描述當前這份pod項目 需要提交到私有庫中,才能讓其他項目通過私有庫引用到當前這份pod項目。
*.podspec 內容格式基本如下:
Pod::Spec.new do |s|
s.name = “demoProject” //項目名
s.version = “1.0.2” //版本號 要和在git上的tag對應
s.summary = “demo”
s.description = <<-DESC
this is a demo
DESC
s.homepage = “git@gitlab.jfz.net:xxxx/demoProject” //項目主頁
s.license = ‘MIT’
s.author = { “young” => “young.huang@jfz.com” } //用戶信息
s.source = { :git => “git@gitlab.jfz.net:xxx/demoProject.git”, :tag => s.version.to_s }//git地址
s.platform = :ios, ‘6.0’ //支持系統、最低版本
s.requires_arc = true //是否使用ARC,如果指定具體文件,則具體的問題使用ARC
s.source_files = ‘Pod/Classes/*/.{h,m}’ //項目核心部分的文件 class下面的所有.h/.m文件
#s.source_files = 'Pod/Classes/**/*'//代碼源文件地址,**/* 表示Classes目錄及其子目錄下所有文件,如果有多個目錄下則用逗號分開,如果需要在項目中分組顯示,這里也要做相應的設置
# s.public_header_files = ‘Pod/Classes/*/.h’ //公開頭文件地址
# s.frameworks = ‘UIKit’, ‘MapKit’ //此pod項目使用到得框架
# s.dependency ‘AFNetworking’, ‘~> 2.3’ //此pod項目依賴的其他pod項目
end
修改pod項目并提交到指定地址 給項目打上tag 這里的tag需要和podspec中配置的tag一樣。
$ git tag 1.0.0
$ git push origin v1.0.0
特別注意 :
1.每次往Pod里面添加文件、圖片、等任何非代碼級別的改動的時候,都需要在Example目錄下面進行一次pod install 或者 pod update一次。
2.版本管理忽略掉pods文件夾 保留 podfile podfile.lock 跟著版本同步
2.創建私有倉庫
首先創建放私有庫(repo) git地址 :
git@gitlab.xxx.net:xxxxx/demoRepo.git
然后在添加一個叫 demoRepo 的本地repo,并指向之前創建好的git地址,控制臺命令:
$ pod repo add demoRepo git@gitlab.xxx.net:xxxxx/demoRepo.git
$ pod repo //查看本地所有repo
私有庫創建好了后,回到之前創建的pod項目下,一般修改好podspec后會進行校驗必須是無錯誤、無警告才能提交。校驗命令:
pod lib lint //只是本地格式校驗
pod spec lint YoungEwm.podspec //這個命令除開校驗格式 還需要校驗遠程地址,鏈接的項目地址等
將修改好的podspec文件push到我們剛剛創建的demoRepo上。加上 –-verbose命令會打印操作日志
$ pod repo push demoRepo demoProject.podspec –-verbose
到最后如果是因為警告原因(warn)無法通過則在push命令后如上 --allow-warnings
即可。成功提交后在我們的demoRepo對應的git remote端就可以看到一個對應版本的 pod spec 文件。
├─ LICENSE
├─ demoProject
│ └─ 1.0.2
│ └─ demoProject.podspec
└─ README.md
3.獲取私有倉庫中的pod項目
上面已經將我們自己創建的項目注冊到了我們自己的私有repo中,在我們的主項目中需要引入這些pod部件的時候。首先在項目的 .xcodeproj
文件同級 創建一個 podfile 文件 文件內容如下:
source ‘https://github.com/CocoaPods/Specs.git’ 引用的源 cocoapods的公用源
source ‘git@gitlab.jfz.net:huangyang/demoRepo.git’ 我們自己的私有源
platform :ios, ‘6.0’
target ‘demoWebView’ do
pod ‘JFZPodsDemo’, ‘~> 1.0.1’ //我們需要引入的pod項目 ~> 表示是 1.0.X 版本級別的更新 前兩位不改變
end
這里面的 platform 版本要和 podspec 里面設置的不能沖突,否則無法引用pod項目
然后重新 pod install 一下就好了
4.刪除repo
如何刪除一個私有Spec Repo,只需要執行一條命令即可:
pod repo remove demoRepo
這樣這個Spec Repo就在本地刪除了,我們還可以通過
pod repo add demoRepo git@coding.net:wtlucky/WTSpecs.git
再把它給加回來。
如果我們要刪除私有Spec Repo下的某一個podspec怎么操作呢,此時無需借助Cocoapods,只需要cd到~/.cocoapods/repos/demoRepo 目錄下,刪掉庫目錄。
~/.cocoapods/repos/demoRepo$ rm -Rf demoRepoXXX
然后在將Git的變動push到遠端倉庫即可。
5.可能遇見的問題
spec文件無法校驗通過
發生原因:
當spec本身格式有錯誤的時候
當引用多個私有repo中得pod項目,直接指向cocoapods查詢不到對應的pod所屬的私有repo
解決辦法 :
在pod repo push 后跟上對repo的地址指向 -- source=。已經添加到本地的repo 可以直接用repo名稱,沒有的使用git地址。
--sources=https://github.com/artsy/Specs,master
6.開發pod項目的其他問題
1.怎么在開發中調試程序
開發過程中,可以修改Podfile文件的,將pod版本指向本地。對應pod的代碼會被引入Development Pods中:
#pod 'Stock', :path => '/Users/xxxx/desktop/workplace/Stock'
2.模塊之間的命名問題
最好以模塊為單位添加不同的前綴。
3.Pod之間的引用
4.tag緩存問題
添加pod的某個tag如0.0.1 到repo后,需要修改代碼但又不想提升tag版本時,注意修改完后清理CocoaPods的本地緩存
$ rm -rf “${HOME}/Library/Caches/CocoaPods”
5.第三方庫的修改,盡量fork再通過pod引用
6.ignore 文件忽略問題
有時候突然想要忽略某個文件,但是跟新 .gitignore 以后,remote 端并沒有馬上刪除這個文件,原因是ignore文件只能忽略沒有加入版本管理的文件,已經被納入了版本管理的文件是無效的
git rm -r --cached .
git add .
git commit -m 'update .gitignore'
7.使用ssh協議(見git使用中得ssh描述)
8.解決ArgumentError - invalid byte sequence in US-ASCII錯誤
修改終端語言、地區等國際化環境變量
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8
9.CI-SSH 問題
#解決ci遠程slave訪問git時,要求驗證私鑰密碼問題
#即,pod install 時,跟新pod的訪問權限問題
#$SSH_PARIVATE_KEY_PASS變量為私鑰密碼
#為了安全在jenkins的環境變量里面設置這個常量
eval $(ssh-agent)
expect << EOF
spawn ssh-add $1
expect "Enter passphrase"
send "$SSH_PRIVATE_KEY_PASS\r"
expect eof
EOF
10.其他知識點
pod 在多人協作的時候 如何保證 發布版本不會跟著開發走動 :
我們從開發過程可以看到 當我們pod install的時候 會出現下面代碼:
Pre-downloading: `Category` from `git@gitlab.xxx.net:xxx_iOS/Category.git`, commit `e244ac83e027b8f6247e702603ecf0209c9d4878`
這里說明 Category這個庫 更新了 pod去拉取Category庫最新的代碼
cocoapods是根據 podfile文件中得 配置去指向指定庫 同時 也有一個pod.lock文件 這個文件用于鎖定 pod拉取代碼的 commit 節點。如下是Category在pod.lock文件中生成的,commit 就是指向對應commit節點。
Category:
:commit: 03c7a540b5c24eda6cea048048adef887cbbc77a
:git: git@gitlab.jfz.net:gxq_iOS/JFZReportModule.git
當然 如果是已經打了tag的不存在這個問題 因為它是按tag去拉取,這里針對的時尚未打tag的庫。
5、CocoaPods高級應用
podfile文件的更多應用
1、pod引用參數
1、Build configurations(編譯配置)
pod 'PonyDebugger', :configurations => ['Debug', 'Beta']
2、Subspecs(子模塊)
pod 'QueryKit', :subspecs => ['Attribute', 'QuerySet']
pod 'QueryKit/Attribute'
3、branch、tag、commit
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :branch => 'dev'
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :tag => '0.7.0'
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :commit => '082f8319af'
4、指定podspec
pod 'JSONKit', :podspec => 'https://example.com/JSONKit.podspec'
2、target
一個工程多個taget需要不同pod配置項的時候
workspace 'xxx.xcworkspace' 指定對應xcworkspace
target :ZipApp do
project 'FastGPS' 指定對應project
pod 'SSZipArchive'
end
使用自定義構建配置
project 'TestProject', 'Mac App Store' => :release, 'Test' => :debug
3、inhibit_all_warnings!
屏蔽cocoapods庫里面的所有警告
inhibit_all_warnings!
or
pod 'SSZipArchive', :inhibit_warnings => true
4、pre_install
這個鉤子允許你在Pods被下載后但是還未安裝前對Pods做一些改變
pre_install do |installer|
# Do something fancy!
end
5、post_install
這個鉤子允許你在生成的Xcode project寫入硬盤或者其他你想執行的操作前做最后的改動
給所有target自定義編譯配置
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['GCC_ENABLE_OBJC_GC'] = 'supported' //配置環境變量等
end
end
end
6、abstract_target
抽象target、當多個target的工程并且工程中各個target之間有很大一部分依賴是相同的時候,我們可以抽象出一個抽象target
抽象target中的所有target都自動繼承抽象target定義的所有依賴
abstract_target 'Shows' do
pod 'ShowsKit'
# The target ShowsiOS has its own copy of ShowsKit (inherited) + ShowWebAuth (added here)
target 'ShowsiOS' do
pod 'ShowWebAuth'
end
# The target ShowsTV has its own copy of ShowsKit (inherited) + ShowTVAuth (added here)
target 'ShowsTV' do
pod 'ShowTVAuth'
end
# Our tests target has its own copy of
# our testing frameworks, and has access
# to ShowsKit as well because it is
# a child of the abstract target 'Shows'
target 'ShowsTests' do
inherit! :search_paths
pod 'Specta'
pod 'Expecta'
end
end
7、其他參數 swift_version、platform、use_frameworks、inherit
swift_version:指定swift版本號
swift_version = '4.0'
platform:指定系統、版本
platform :ios, '4.0'
platform :ios
use_frameworks:使用動態庫
use_frameworks!
inherit! :search_paths
明確指定繼承于父層的所有pod,默認就是繼承的