MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C中的Carthage依赖管理实践

2021-02-033.5k 阅读

什么是 Carthage

Carthage 是一个轻量级的、基于二进制框架的依赖管理工具,专为 iOS、macOS、watchOS 和 tvOS 项目设计。与其他依赖管理工具(如 CocoaPods)不同,Carthage 不会修改项目的 Xcode 配置文件(.xcodeproj),而是通过生成二进制框架,让开发者手动将这些框架添加到项目中。这使得 Carthage 在保持项目原有结构的同时,能够有效地管理项目依赖。

Carthage 的优势

  1. 轻量级:Carthage 不会在项目中引入过多的额外配置文件,相比于一些其他依赖管理工具,它对项目的侵入性较小。这使得项目结构保持相对简洁,对于已经有复杂项目结构的工程来说,不会带来额外的混乱。
  2. 基于二进制框架:通过生成二进制框架,Carthage 加快了依赖的集成过程。开发者无需担心依赖库的编译过程,直接使用预编译好的二进制文件,提高了项目的构建速度。而且二进制框架也减少了项目中暴露的源代码,在一定程度上增强了代码的安全性。
  3. 易于集成:Carthage 的集成过程相对简单,主要通过编写 Cartfile 文件来管理依赖,不需要复杂的 Xcode 配置更改。

安装 Carthage

  1. 使用 Homebrew 安装:如果你的 macOS 系统上安装了 Homebrew(一个流行的包管理器),可以通过以下命令安装 Carthage:
brew install carthage
  1. 验证安装:安装完成后,可以通过以下命令验证 Carthage 是否安装成功:
carthage version

该命令会输出版本号,如果输出了版本号,则说明 Carthage 安装成功。

创建 Cartfile

  1. Cartfile 基础语法:在项目的根目录下创建一个名为 Cartfile 的文件。Cartfile 用于指定项目所依赖的库及其版本。例如,要添加 Alamofire(一个流行的网络请求库)到项目中,可以在 Cartfile 中添加以下内容:
github "Alamofire/Alamofire" ~> 5.0

这里使用 github 关键字表示依赖库托管在 GitHub 上,Alamofire/Alamofire 是库的仓库路径,~> 5.0 表示使用 5.0 及以上但小于 6.0 的版本。

  1. 多个依赖:如果项目有多个依赖,可以在 Cartfile 中逐行添加。例如,同时添加 Alamofire 和 Kingfisher(一个图片加载库):
github "Alamofire/Alamofire" ~> 5.0
github "onevcat/Kingfisher" ~> 7.0

使用 Carthage 集成依赖

  1. 更新依赖:在项目根目录下打开终端,执行以下命令来更新依赖:
carthage update

该命令会根据 Cartfile 中的配置,下载并构建依赖库。构建完成后,会在项目根目录下生成一个 Carthage 文件夹,里面包含了下载和构建好的依赖框架。

  1. 添加框架到项目:打开 Xcode 项目,将 Carthage/Build 目录下对应的平台(如 iOS)中的框架文件拖到 Xcode 项目的 Frameworks 组中。在拖入时,确保勾选了 Copy items if needed 选项,这样可以将框架文件复制到项目目录中。

  2. 配置 Build Phases:为了确保应用在运行时能够找到这些框架,需要在 Build Phases 中进行配置。在 Xcode 项目中,选择 Build Phases 标签,点击 + 按钮,选择 New Run Script Phase。在新添加的 Run Script 中,输入以下内容:

/usr/local/bin/carthage copy-frameworks

然后在 Input Files 中添加 $(SRCROOT)/Carthage/Build/iOS/*.framework(根据实际平台修改,如 macOS 则为 $(SRCROOT)/Carthage/Build/macOS/*.framework)。这样配置后,Xcode 在构建项目时会将依赖框架正确地复制到应用包中。

在 Objective-C 项目中使用依赖库

  1. 导入框架:在需要使用依赖库的 Objective-C 文件中,使用 #import 导入框架头文件。例如,使用 Alamofire 进行网络请求:
#import <Alamofire/Alamofire.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [Alamofire request:@"https://httpbin.org/get" method:.GET parameters:nil headers:nil completionHandler:^(AFDataResponse * _Nonnull response) {
        if (response.result.isSuccess) {
            NSLog(@"请求成功: %@", response.result.value);
        } else {
            NSLog(@"请求失败: %@", response.result.error);
        }
    }];
}

@end
  1. 解决框架冲突:在使用多个依赖库时,可能会遇到框架冲突的问题,例如两个库依赖了同一个库的不同版本。此时,可以通过指定依赖库的精确版本来解决冲突。在 Cartfile 中,将版本号指定为具体的版本,而不是使用范围。例如:
github "Alamofire/Alamofire" == 5.0.1

这样就强制使用 Alamofire 的 5.0.1 版本,避免与其他库的版本冲突。

Carthage 高级配置

  1. 使用 Cartfile.resolvedCarthage 在更新依赖后会生成一个 Cartfile.resolved 文件,该文件记录了实际使用的依赖库版本。这个文件对于团队协作非常重要,它可以确保团队成员使用相同版本的依赖库。在团队开发中,应该将 Cartfile.resolved 提交到版本控制系统(如 Git)中。

  2. 自定义构建脚本:Carthage 允许开发者通过自定义构建脚本来对依赖库进行更细粒度的控制。例如,可以在 Cartfile 中为某个依赖指定自定义的构建脚本:

github "MyCustomRepo/MyCustomLibrary" "main" do
    script "./custom_build_script.sh"
end

custom_build_script.sh 脚本中,可以编写自己的构建逻辑,如修改编译参数、添加额外的资源等。

  1. 使用预编译框架:为了进一步提高构建速度,可以使用预编译的框架。Carthage 支持从远程服务器下载预编译好的框架,而不是每次都在本地构建。要实现这一点,需要在远程服务器上提供预编译的框架,并在 Cartfile 中进行相应的配置。例如:
github "MyRepo/MyLibrary" do
    binary "https://example.com/my_library_binary.json"
end

其中 my_library_binary.json 文件包含了预编译框架的下载地址、校验和等信息。

常见问题及解决方法

  1. 构建失败:如果在执行 carthage update 时构建失败,可能是依赖库的构建环境问题。首先检查是否安装了依赖库所需的工具和依赖,例如某些库可能依赖特定版本的 Xcode 或命令行工具。另外,可以尝试在 Cartfile 中指定依赖库的特定版本,看是否能解决问题。

  2. 找不到框架:如果在运行项目时出现找不到框架的错误,首先检查 Build Phases 中的配置是否正确,特别是 Run ScriptInput Files 的设置。确保框架文件已经正确复制到项目目录中,并且在 Link Binary With Libraries 中也添加了相应的框架。

  3. 版本冲突:如前面提到的版本冲突问题,除了精确指定版本号外,还可以尝试使用 carthage update --no-use-binaries 命令,强制 Carthage 从源代码构建依赖库,这样可能会解决一些版本兼容性问题,但会增加构建时间。

Carthage 与其他依赖管理工具的比较

  1. 与 CocoaPods 的比较

    • 项目侵入性:CocoaPods 通过修改 .xcodeproj 文件来管理依赖,会在项目中添加 Pods 文件夹和 Podfile 等配置文件,对项目结构有一定的侵入性。而 Carthage 相对轻量级,只生成 Carthage 文件夹和 Cartfile 等,对项目原有结构影响较小。
    • 构建速度:Carthage 基于二进制框架,通常构建速度较快,因为不需要每次都重新编译依赖库的源代码。CocoaPods 每次更新依赖都需要重新编译所有依赖库,在依赖较多时构建时间会较长。
    • 灵活性:CocoaPods 有丰富的插件生态系统,可以进行更复杂的依赖管理和项目配置。Carthage 则更专注于简单的依赖集成,通过自定义构建脚本等方式也能实现一定的灵活性,但整体上不如 CocoaPods 灵活。
  2. 与 Swift Package Manager(SPM)的比较

    • 语言支持:SPM 主要用于 Swift 项目,对 Objective-C 的支持相对较弱。Carthage 则对 Objective-C 和 Swift 都有较好的支持,适用于混合语言的项目。
    • 集成方式:SPM 集成到 Xcode 原生的构建系统中,使用起来相对方便。Carthage 需要手动添加框架和配置 Build Phases,集成过程相对复杂一些,但也因此更加灵活,可以更好地适应不同的项目结构。

总结 Carthage 的适用场景

  1. 小型项目:对于小型的 Objective-C 项目,Carthage 的轻量级特性使其成为一个很好的选择。它不会给项目带来过多的配置负担,同时能快速集成常用的依赖库,加快开发速度。
  2. 对构建速度要求高的项目:如果项目对构建速度有较高的要求,Carthage 的二进制框架特性可以显著提高构建效率,减少开发过程中的等待时间。
  3. 需要保持项目原有结构的项目:当项目已经有复杂的结构,并且不希望依赖管理工具对其进行大规模修改时,Carthage 的低侵入性特点就体现出优势,可以在不改变项目核心结构的前提下管理依赖。

在实际项目开发中,需要根据项目的具体需求和特点来选择合适的依赖管理工具,Carthage 在 Objective-C 项目中为开发者提供了一种高效、灵活的依赖管理方式。通过合理使用 Carthage 的各种特性和配置,可以有效地提升项目的开发效率和稳定性。