iOS 轻量级包管理工具Carthage了解下

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,兼容httpsfile://

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文件夹,我们会看到BuildChekouts文件夹。Carthage.resolved文件夹类比就是Podfile.lock用来锁定版本信息的。一般团队开发,我们会把这个文件提交到仓库,避免出现不同同学安装不同的依赖。carthage update其实就是carthage buildcarthage checkout的集合,因此会生成上述提到的两个文件夹。Build目录下放置编译好的默认动态库,checkouts默认放置检出的源码。

  • 3.添加Framework到项目中

打开Xcode项目,选择Target->General选项卡,然后再底部找到Linked Frameworks and Libraries。打开项目根目录下Carthage/Build/iOS,找到你需要的Framework,然后把这几个库拖进来。这边我用Swift更新的时候死活更新下来,就用OC的两个库代替了,反正也就是对应的AlamofireSnapKit这两个库
iOS 轻量级包管理工具Carthage了解下_第1张图片
iOS 轻量级包管理工具Carthage了解下_第2张图片

然后找到target->build phase选项卡,添加一个New Run Script Phase,然后添加新的脚本/usr/local/bin/catthage copy-frameworks。点击下面的Input Files,给对应的库添加。
iOS 轻量级包管理工具Carthage了解下_第3张图片
这里在目录下创建了一个input.xcfilelistoutput.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

你可能感兴趣的:(工具集,基础知识)