我们已经熟知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.pkg
,然后根据介绍安装。如果你通过CLI
安装了pkg,可能还需要执行sudo chown -R $(whoami) /usr/local
brew
安装,先执行brew update
更新下仓库,然后brew install carthage
即可。但是如果你之前安装过二进制版本,你应该从/Library/Frameworks/CarthageKit.framework
这里把文件移除。首先用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
是一样的,就不展开了。
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
默认放置检出的源码。
打开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
经常制作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