Why Carthage?
我們已經熟知Cocoapods
了,對於工程來說,幫我們自動創建Xcode WorkSpace
和所有的依賴,對於依賴庫來說,用來做本地local pod
或者遠程pod
都非常好用,我們只要編寫好對應的podspec
文件,Cococapods
會幫我們生成所有的依賴配置集成到項目。可以認爲他是一體機,入侵性的幫我們管理好了Xcode項目文件。對於不需要手動管理的同學,這已經是一個長期好用的工具了,那爲什麼還要有Carthage
呢?
1、去中心化管理工具
沒有集中的podspec
倉庫管理過程,可以減少維護工作以及集中倉庫掛掉的問題,每次只要更新對應的庫即可。
2、DIY 手動集成
Checkout
項目到指定目錄,根據當前下載的源碼默認直接編譯成二進制用xcodebuild
,這個和podpackage
一樣,問題是這個維護的問題,因此我們這邊開始瞭解新的構建工具。對於編譯的二進制庫,用戶手動導入項目使用。對於會用的同學來說,這簡直就是松耦合的過程,但是對於依賴Cocoapods
的朋友,這會覺得很麻煩,畢竟DIY的過程對不同的朋友來說感受是不同的。對我來說,我要的就是這個Carthage Build
的這個工具,本文就簡單介紹下全過程。
3、對框架作者無感
Carthage
想盡可能簡單的做一個項目管理工具,他不會參與承擔Xcode的構建過程,也不會對框架的開發者帶來額外的工作。雖然Cocoapods
給框架帶來了非常強大的集成功能,但是前提是要爲你的庫編寫對應的podspec
文件,比如包括project元數據,以及告訴他如何進行依賴編譯,這些功能Carthage
官方說的是不會有,我們是非侵入性的,代價是需要手動管理依賴和配置。
4、提高編譯速度
根據上面的三點,有個很好的消息是,他能和Cocoapods
無縫銜接,兩者可以共存,而且幫我們編譯好了二進制,對於一些編譯很長時間的庫打包成二進制,或者不常用的庫打包成二進制,存入文件服務器,寫好podspec
指向zip包,然後結合Podfile
文件進行依賴管理,同時可以結合CI
優化編譯和打包時間。
Carthage 安裝
- 手動:從release中下載對應的
Carthage.pkg
,然後根據介紹安裝。如果你通過CLI
安裝了pkg,可能還需要執行sudo chown -R $(whoami) /usr/local
- Homebrew: 通過
brew
安裝,先執行brew update
更新下倉庫,然後brew install carthage
即可。但是如果你之前安裝過二進制版本,你應該從/Library/Frameworks/CarthageKit.framework
這裏把文件移除。
給你的App添加Carthage生成的Framework
- 1.Carthage 文件創建
首先用Xcode創建一個簡單的CarthageDemo1
工程
cd ~/Desktop/CarthageDemo1
touch Cartfile
在文件中輸入內容如下
github "AFNetworking/AFNetworking" == 3.1.0
github "Masonry/Masonry" == 0.6.3
github "YYModel/YYModel"
該文件就和Cocoapods
中的Podfile
是一樣的,他支持三種類型GitHub repositories
, Git repositories
, 和 binary-only frameworks served over https
GitHub repositories
github "ReactiveCocoa/ReactiveCocoa" # GitHub.com
github "https://enterprise.local/ghe/desktop/git-error-translations" # GitHub Enterprise
github
指定owner/repo
的格式
Git repositories
這個也是我們最熟知的git地址
git "https://enterprise.local/desktop/git-error-translations2.git"
Binary only frameworks
支持編譯好的二進制.framework
,兼容https
和file://
binary "https://my.domain.com/release/MyFramework.json" // Remote Hosted
binary "file:///some/Path/MyFramework.json" // Locally hosted at file path
binary "relative/path/MyFramework.json" // Locally hosted at relative path to CWD
binary "/absolute/path/MyFramework.json" // Locally hosted at absolute path
對應的json
二進制工程spec
{
"1.0": "https://my.domain.com/release/1.0.0/framework.zip",
"1.0.1": "https://my.domain.com/release/1.0.1/framework.zip"
}
該json
文件必須是版本和zip地址的對應,不能用branchs
,tags
,commit
,也就是在你打包好的二進制工程中,做個json
文件,版本指向遠程https
文件服務器或者lfs管理的zip地址即可。
以上三種方式制定的地址,後面可以和Podfile
一樣跟版本號 ==
,->
,~>
,這三個和Cocoapods
是一樣的,就不展開了。
- 2.安裝依賴
carthage update --platform iOS --no-use-binaries
官方介紹是沒有後面的可選參數的,--platform iOS
是指定平臺默認是全平臺架構的,--no-use-binaries
是不用預編譯的二進制,用源碼重新編譯二進制,如果不指定,網絡不好的情況下一直會出現如下錯誤
*** Skipped installing Masonry.framework binary due to the error:
"GitHub API request failed: networkError(Error Domain=NSURLErrorDomain Code=-1004 "Could not connect to
the server." UserInfo={NSUnderlyingError=0x7fdc00c1e8a0 {Error Domain=kCFErrorDomainCFNetwork Code=-1004 "
(null)" UserInfo={_kCFStreamErrorCodeKey=61, _kCFStreamErrorDomainKey=1}},
NSErrorFailingURLStringKey=https://api.github.com/repositories/11570469/releases/tags/v0.6.3,
NSErrorFailingURLKey=https://api.github.com/repositories/11570469/releases/tags/v0.6.3,
_kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=61, NSLocalizedDescription=Could not connect to the
server.})"
Falling back to building from the source
如果想了解更多,可使用carthage help update
查看。如果只需要更新某個第三方庫
carthage update xxxxxx --platform iOS
當命令執行完之後,Cartfile
同級目錄下會出現一個Carthage
文件夾和Carthage.resolved
文件。打開Carthage
文件夾,我們會看到Build
和Chekouts
文件夾。Carthage.resolved
文件夾類比就是Podfile.lock
用來鎖定版本信息的。一般團隊開發,我們會把這個文件提交到倉庫,避免出現不同同學安裝不同的依賴。carthage update
其實就是carthage build
和carthage checkout
的集合,因此會生成上述提到的兩個文件夾。Build
目錄下放置編譯好的默認動態庫,checkouts
默認放置檢出的源碼。
- 3.添加Framework到項目中
打開Xcode項目,選擇Target->General
選項卡,然後再底部找到Linked Frameworks and Libraries
。打開項目根目錄下Carthage/Build/iOS
,找到你需要的Framework,然後把這幾個庫拖進來。這邊我用Swift
更新的時候死活更新下來,就用OC的兩個庫代替了,反正也就是對應的Alamofire
和SnapKit
這兩個庫
然後找到target->build phase
選項卡,添加一個New Run Script Phase
,然後添加新的腳本/usr/local/bin/catthage copy-frameworks
。點擊下面的Input Files
,給對應的庫添加。
這裏在目錄下創建了一個input.xcfilelist
和output.xcfilelist
,在input
下面添加
$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework
$(SRCROOT)/Carthage/Build/iOS/Snapkit.framework
在output
下添加
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Alamofire.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/SnapKit.framework
這裏添加output
的目的是爲了提高編譯速度。只有當input變化的時候或者output文件不存在的時候,纔會在編譯的時候執行copy-framework
的腳本。
以上的操作,就可以愉快的進行代碼編寫了。
如果出現以下報錯,是因爲部署以你App的第三方庫編譯的時候選擇了Code Coverage
,比如AFNetworking
,因此我們需要給對應的工程也添加,或者庫編譯成二進制的時候自己手動勾選去掉
Undefined symbols ___llvm_profile_runtime
方法1、-fprofile-instr-generate to Build Settings > Linking > Other Linker Flags
方法2、Edit Scheme -> Test -> Options -> Code Coverage
製作自己的Carthage庫
經常製作Cocoapods
庫的同學對podspec
文件那應該相當熟悉了,每次都要編寫,那麼Carthage
就相當簡單了。同樣用Cocoapods
的方式測試一下
1、新建一個動態庫
pod lib create JXLiveManager
Carthage
編譯的時候是根據.xcodeproj
(這裏是xcworkspace
)的shared scheme來查找的,因此我們在Manager Schemes
中,需要把對應的scheme
勾選爲Shared。
這裏可以看到,xcworkspace
下,JXLiveManager
對應的工程下有一個JXLiveManager-Example
工程可以編譯,Pods
下就有三個可以編譯的文件,其中JXLIveManager
默認是動態庫,其他兩個都是靜態庫,稍後編譯產物可以看到,您也可以再mach-o
中查看。
如果你想讓所有的Scheme
都能編譯成功
cd Example
carthage build --no-skip-current
此時會生成一個Carthage/Build
的文件夾,裏面可以查看編譯完成後的二進制文件,區分動態庫和靜態庫
2、解決編譯失敗問題
當你執行carthage build --no-skip-current
如果失敗了,沒有編譯產物,試着跑一下xcodebuild -scheme SCHEME -workspace WORKSPACE build
或者執行 xcodebuild -scheme SCHEME -project PROJECT build
,看看是否會出現一樣的錯誤,控制檯能打印出詳細的信息進行調試。如果你有多個版本的Xcode,直接修改即可Xcode-->Preference-->Locations-->Command Line Tools
修改即可。
3、Release
以上兩步操作後,沒有問題的話,就可以和Cocoapods
一樣提交了,只是這裏不需要驗證podspec
文件了,直接推入遠程倉庫即可。不過記得打tag
4、Archive
mikejingdeMBP:Example MKJ$ carthage archive JXLiveManager
*** Found Carthage/Build/iOS/JXLiveManager.framework
*** Found Carthage/Build/iOS/JXLiveManager.framework.dSYM
*** Found Carthage/Build/iOS/JXLiveManager.framework
*** Found Carthage/Build/iOS/JXLiveManager.framework.dSYM
*** Found Carthage/Build/iOS/2EC988C1-5947-3677-8933-C1AFA435AAD9.bcsymbolmap
*** Found Carthage/Build/iOS/C91C35F6-77D9-3CBE-A763-20B45F917C22.bcsymbolmap
*** Found Carthage/Build/iOS/8D3101C1-A4B1-3685-B908-07F98610864F.bcsymbolmap
*** Found Carthage/Build/iOS/8D3101C1-A4B1-3685-B908-07F98610864F.bcsymbolmap
*** Found Carthage/Build/iOS/C91C35F6-77D9-3CBE-A763-20B45F917C22.bcsymbolmap
*** Found Carthage/Build/iOS/2EC988C1-5947-3677-8933-C1AFA435AAD9.bcsymbolmap
*** Found Carthage/Build/iOS/F409B1FF-32B1-3DA3-B6CD-4660A474960E.bcsymbolmap
*** Found Carthage/Build/iOS/F409B1FF-32B1-3DA3-B6CD-4660A474960E.bcsymbolmap
*** Created JXLiveManager.framework.zip
正常情況下,前三步驟已經完全可以了,但是如果你要在提交的時候預編譯打包成zip也可以執行archive
命令,Carthage
會在當前目錄下把二進制產物打包成zip。可以方便後續的CI集成或者Binary only frameworks
的json編寫
後續
上面先對比了Cocoapods
,然後集成到項目做了測試,最後用自己做的第三方庫做了Demo。那麼上面提到的都是默認的動態庫製作,由於一般我們的項目都還是Cocoapods
管理的,而且過多的動態庫會影響啓動時間,下一個文章將記錄下如何優雅的用Carthage
打包靜態Framework