Carthage 新手教程

Carthage 与 Cocoapods 的不同

Cocoapods 是由来已久的 Cocoa 依赖管理工具,那么为什么 Carthage 项目被创建?

首先,Cocoapods(默认情况下)会自动的为你的应用程序和所有依赖创建和更新 Xcode workspace。Carthage 用 xcodebuild 构建框架(framework)的二进制文件,但是并没有将他们整合到用户项目中。Cocoapods 的目的是让用户使用起来更简单,而 Carthage 则是更灵活,减少对项目的侵入性。

Cocoapods 的目标在其README文件中有如下描述:

… to improve discoverability of, and engagement in, third party open-source libraries, by creating a more centralized ecosystem.

对比之下,Carthage 被创建成一个松散(decentralized)的依赖管理者,没有中心项目清单,这减少了维护工作并避免了任何中心故障点(通俗的讲就是去中心化)。然而,项目被发现就变的更加困难 – 用户必须去使用 GitHub 的 Trending 页面或者其他类似的页面(Cocoapods 就比较简单的可以在终端搜索需要使用的库)。

Cocoapods 项目还必须具有所谓的 podspec 文件,其中包括有关项目的元数据,并指定应如何构建它。Carthage 使用 xcodebuild 去构建依赖,而不是将它们集成到单个工作区中,它没有类似的规范文件,但你的依赖项必须包含到自己的 Xcode 项目中,该项目描述了如何构建其产品。

最终,我们创建了 Carthage,因为我们想要一个最简单的工具 – 一个可以完成工作而不必承担 Xcode 责任的依赖管理器,并且并没有为框架作者创造额外的工作。Cocoapods 提供了许多惊人的功能,但是在 Carthage 中,这些功能永远不会出现,因为这会增加额外的复杂性。

Carthage 安装

使用 homebrew 安装

1
brew install carthage

查看版本和升级

1
2
3
4
// 查看版本:
carthage version
// 升级:
brew upgrade carthage

卸载

1
brew uninstall carthage

Carthage 配置第三方库(iOS,tvOS,watchOS)

创建 Cartfile 文件

1
2
cd to your project
touch Cartfile

用 Xcode 打开/编辑 Cartfile

1
open -a Xcode Cartfile

添加依赖库

1
2
github "Alamofire/Alamofire" == 4.5
github "Alamofire/AlamofireImage" ~> 3.2

现在支持的三个来源是 GitHub 存储库,Git 存储库和通过 https 提供的仅二进制框架。未来可能会添加其他可能的来源。如果你想看到具体的东西,请提 issue

GitHub Repositories

使用 github 关键字指定 GitHub 存储库(GitHub.comGitHub Enterprise):

1
2
github "ReactiveCocoa/ReactiveCocoa" # GitHub.com
github "https://enterprise.local/ghe/desktop/git-error-translations" # GitHub Enterprise

github 源是用于 owner/repo 表单指定或通过其 web API 使用预构建的二进制下载功能,因此对 github 源 使用 gitssh 协议是没有意义的,并且这是一个错误。

Git repositories

其他 Git 存储库使用 git 关键字指定:

1
git "https://enterprise.local/desktop/git-error-translations2.git"

Binary only frameworks

仅作为已编译的二进制文件 .frameworks 提供的依赖项使用 binary 关键字和 https:// 链接,file:// 链接,或没有方案的相对或绝对路径,返回二进制项目规范

1
2
3
4
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

版本要求

Carthage 支持多种版本要求:

  1. >= 1.0 指“1.0 及以上版本”。
  2. ~> 1.0 指“1.x 版本”
  3. == 1.0 指“版本为 1.0”
  4. "some-branch-or-tag-or-commit" 特指 git 对象(git rev-parse 任何内容都被允许)。
    • Note:二进制源 不支持这种形式。

如果没有指定任何版本,任何版本的依赖都将被允许(默认使用最新版本)。

Example Cartfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Require version 2.3.1 or later
github "ReactiveCocoa/ReactiveCocoa" >= 2.3.1

# Require version 1.x
github "Mantle/Mantle" ~> 1.0 # (1.0 or later, but less than 2.0)

# Require exactly version 0.4.1
github "jspahrsummers/libextobjc" == 0.4.1

# Use the latest version
github "jspahrsummers/xcconfigs"

# Use the branch
github "jspahrsummers/xcconfigs" "branch"

# Use a project from GitHub Enterprise
github "https://enterprise.local/ghe/desktop/git-error-translations"

# Use a project from any arbitrary server, on the "development" branch
git "https://enterprise.local/desktop/git-error-translations2.git" "development"

# Use a local project
git "file:///directory/to/project" "branch"

# A binary only framework
binary "https://my.domain.com/release/MyFramework.json" ~> 2.3

# A binary only framework via file: url
binary "file:///some/local/path/MyFramework.json" ~> 2.3

# A binary only framework via local relative path from Current Working Directory to binary project specification
binary "relative/path/MyFramework.json" ~> 2.3

# A binary only framework via absolute path to binary project specification
binary "/absolute/path/MyFramework.json" ~> 2.3

安装/编辑 Cartfile 中的项目

clone 项目,然后编译成 framework

1
2
3
// 不指定 platform 会为所有的平台编译(Mac / iOS / tvOS / watchOS)
// 查看更多关于 update 命令的选项:`carthage help update`
carthage update --platform iOS

Cartfile 利用 xcode-select 命令来编译 framework,如果你想用其他版的 Xcode 进行编译,执行下面这条命令,把 xcode-select 的路径改为另一版本 Xcode 就可以。

1
sudo xcode-select -s /Applications/Xcode-beta.app/Contents/Developer

所有的文件会被编译到当前路径的 Carthage 文件夹中:

1
2
// 打开文件夹
open Carthage

Carthage 文件夹中文件说明:

Cartfile.resolved

运行 carthage update --platform iOS 命令后,一个叫 Cartfile.resolved 的文件将会被创建到 Cartfile 同级目录下。此文件准确指定了每个依赖项选择的版本,并列出了所有依赖项(甚至是嵌套的版本)。

强烈建议将该文件加入到版本控制中,告知其他开发者,当前使用的版本。

虽然 Cartfile.resolved 文件是人类可读和可扩展的,但你不能修改它。文件的格式非常严格,列出依赖项的顺序对于构建过程很重要。

Carthage 文件夹

  • Build
    包含对应平台编译好的Framework
  • Checkouts
    包含编译 framework 所使用的源代码(除非你使用 submodules ,否则不要修改这里的代码,carthage updatecarthage checkout 会覆盖这里的代码,清除你的修改)。

With submodules

如果在引导项目的依赖项时给出了 --use-submodules 标志,updated 或者 checked out Carthage/Checkouts 中的依赖项将作为 Git 子模块(submodules)提供。这允许你对依赖项进行更改,并提交这些更改。

更新Framework的版本

打开 Cartfile

1
open -a Xcode Cartfile

修改版本

1
2
// github "Alamofire/Alamofire" == 4.5
github "Alamofire/Alamofire" ~> 4.5.0

更新

1
carthage update --platform iOS

更新指定库

1
carthage update SVProgressHUD --platform iOS

引入 Carthage 依赖库到 Xcode

  1. Carthage -> Build 中找到需要添加的 framework
  2. 拖拽对应的 framework 到 Xcode 工程的 Linked Frameworks and Libraries 中。

  1. 进入工程的 target -> Build Phases,点击 +,添加 New Run Script Phase:

添加如下脚本命令:

1
/usr/local/bin/carthage copy-frameworks

Input Files 下添加要使用的框架的路径。例如:

1
$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework

将复制框架的路径添加到 Output Files。例如:

1
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Alamofire.framework

为什么需要指定 Output Files

使用 Carthage 来管理第三方库,在编译并运行 App 的时候,会有一个阶段叫:Carthage Copy Frameworks。这个阶段通过跑一个脚本的形式把所有依赖的第三方库都复制到 App 的目录里。

这个阶段通常会花 1~x 秒不等,这取决于你的 App 依赖的第三方库数量。默认情况下,每次你 Build & Run 的时候,都会进行一次这个操作——尽管你的第三方库没有任何改变。

所以我们需要指定 Output Files,在 Output Files 指定输出文件的情况下,Xcode 只会在 framework 发生更改时去进行 copy framework 操作,这样就节省了时间。