Swift Package Manager: 从零开始构建与集成 – wiki词典


Swift Package Manager: 从零开始构建与集成

Swift Package Manager (SPM) 是 Apple 官方推出并推荐的依赖管理工具,用于自动化 Swift 代码的分发。它与 Swift 构建系统深度集成,提供了一种统一的方式来管理项目中的第三方库,并简化了在不同平台(iOS, macOS, tvOS, watchOS, Linux, Windows)上共享代码的流程。

本文将从零开始,详细介绍如何创建一个 Swift Package,以及如何将其集成到您的 Xcode 项目中。

1. SPM 简介与优势

在 SPM 出现之前,iOS/macOS 开发者主要依赖 CocoaPods 和 Carthage 来管理第三方库。SPM 的出现解决了这些工具的一些痛点,并带来了以下优势:

  • 原生支持: 作为 Swift 工具链的一部分,SPM 无缝集成于 Xcode 和 Swift 构建系统,无需额外安装其他工具。
  • 跨平台: 支持所有 Swift 运行的平台,包括 Apple 平台、Linux 和 Windows。
  • 易用性: 通过简单的 Swift 语法定义 Package.swift 文件,即可声明依赖关系。
  • 版本控制集成: 直接利用 Git 仓库进行版本管理,方便地指定依赖的版本。
  • 模块化: 鼓励开发者将代码组织成独立的模块,提高代码复用性和可维护性。

2. 环境准备

要开始使用 SPM,您需要:

  • Xcode: 推荐使用最新稳定版 Xcode,它内置了 Swift 和 SPM。
  • macOS: 虽然 SPM 也支持 Linux 和 Windows,但在 macOS 上结合 Xcode 使用是主流。

3. Part 1: 构建您的第一个 Swift Package

我们将创建一个简单的 Swift Package,包含一个计算器功能。

3.1 初始化一个新的 Swift Package

首先,打开终端,导航到您希望创建项目的目录,然后执行以下命令:

bash
mkdir MyCalculatorPackage
cd MyCalculatorPackage
swift package init --type library

  • mkdir MyCalculatorPackage: 创建一个新的文件夹作为您的 Package 根目录。
  • cd MyCalculatorPackage: 进入该目录。
  • swift package init --type library: 初始化一个库类型的 Swift Package。如果您想创建一个可执行的命令行工具,可以使用 --type executable

执行后,您会看到如下的文件结构:

.
├── Sources/
│ └── MyCalculatorPackage/
│ └── MyCalculatorPackage.swift
├── Tests/
│ └── MyCalculatorPackageTests/
│ └── MyCalculatorPackageTests.swift
├── .gitignore
└── Package.swift

  • Sources: 存放您的源代码。每个子文件夹代表一个 Target。
  • Tests: 存放您的单元测试代码。
  • Package.swift: 包的清单文件,定义了包的名称、产品、目标和依赖。
  • .gitignore: Git 忽略文件。

3.2 理解 Package.swift 文件

打开 Package.swift 文件,内容大致如下:

“`swift
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift tools required to build this package.

import PackageDescription

let package = Package(
name: “MyCalculatorPackage”,
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: “MyCalculatorPackage”,
targets: [“MyCalculatorPackage”]),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: “MyCalculatorPackage”),
.testTarget(
name: “MyCalculatorPackageTests”,
dependencies: [“MyCalculatorPackage”]),
]
)
“`

  • swift-tools-version: 定义了构建此包所需的最低 Swift 工具版本。
  • name: 包的名称。
  • products: 定义了此包公开的产品。
    • .library: 定义一个库产品,可以被其他项目或包引用。name 是库的名称,targets 是该库包含的目标。
  • targets: 定义了包中的模块。
    • .target: 定义一个源代码目标。默认情况下,它的源文件在 Sources/<target name> 目录下。
    • .testTarget: 定义一个测试目标。它通常依赖于它所测试的源代码目标。
    • dependencies: 指定此目标依赖的其他目标或包产品。

3.3 编写 Package 代码

编辑 Sources/MyCalculatorPackage/MyCalculatorPackage.swift 文件,添加一个简单的计算器结构体:

“`swift
import Foundation

public struct Calculator {
public init() {}

public func add(_ a: Int, _ b: Int) -> Int {
    return a + b
}

public func subtract(_ a: Int, _ b: Int) -> Int {
    return a - b
}

public func multiply(_ a: Int, _ b: Int) -> Int {
    return a * b
}

public func divide(_ a: Int, _ b: Int) -> Double? {
    guard b != 0 else { return nil }
    return Double(a) / Double(b)
}

}
“`

注意:为了使 Calculator 结构体和其方法能在外部使用,它们必须声明为 public

3.4 编写测试代码

编辑 Tests/MyCalculatorPackageTests/MyCalculatorPackageTests.swift 文件,为计算器功能添加测试:

“`swift
import XCTest
@testable import MyCalculatorPackage // 使用 @testable 导入内部类型进行测试

final class MyCalculatorPackageTests: XCTestCase {
func testAdd() {
let calculator = Calculator()
XCTAssertEqual(calculator.add(1, 2), 3)
XCTAssertEqual(calculator.add(-1, 1), 0)
}

func testSubtract() {
    let calculator = Calculator()
    XCTAssertEqual(calculator.subtract(5, 3), 2)
    XCTAssertEqual(calculator.subtract(3, 5), -2)
}

func testMultiply() {
    let calculator = Calculator()
    XCTAssertEqual(calculator.multiply(2, 3), 6)
    XCTAssertEqual(calculator.multiply(-2, 3), -6)
}

func testDivide() {
    let calculator = Calculator()
    XCTAssertEqual(calculator.divide(6, 2), 3.0)
    XCTAssertNil(calculator.divide(6, 0)) // 测试除以零的情况
}

}
“`

3.5 构建与测试 Package

MyCalculatorPackage 目录下,您可以通过终端命令来构建和运行测试:

bash
swift build // 构建包
swift test // 运行包中的所有测试

如果一切顺利,您将看到构建成功和测试通过的输出。

4. Part 2: 集成 Swift Package 到 Xcode 项目

现在我们已经有了一个可用的 Swift Package,接下来是如何将其集成到您的 iOS 或 macOS 项目中。

4.1 创建一个新的 Xcode 项目

如果您还没有,请创建一个新的 Xcode 项目 (例如:一个 iOS App)。

4.2 添加 Swift Package 依赖 (推荐方式:Xcode UI)

这是最常见和最简单的方法:

  1. 在 Xcode 中,选择您的项目导航器中的项目文件 (顶部的蓝色图标)。
  2. 在主窗口中,选择 “Project” 或 “Target” (通常是您的应用程序 Target),然后点击 “Package Dependencies” 选项卡。
  3. 点击底部的 “+” 按钮。
  4. 在弹出的对话框中,您有几种方式添加依赖:
    • 远程仓库: 如果您的 Package 已经上传到 Git 仓库 (如 GitHub),可以直接粘贴仓库的 URL (e.g., https://github.com/your-username/MyCalculatorPackage.git)。
    • 本地包: 对于仍在开发中的本地包,您可以点击 “Add Local…” 并选择您的 MyCalculatorPackage 文件夹。Xcode 会自动识别 Package.swift 文件。
  5. 添加 URL 后,Xcode 会解析该仓库,并允许您选择依赖规则 (Version, Branch, Commit)。对于初次集成,您可以选择 “Up to Next Major Version” 并使用默认版本。
  6. 点击 “Add Package” 完成添加。
  7. Xcode 会将包添加到您的项目,并显示在 “Package Dependencies” 列表中。同时,在左侧的项目导航器中,您会看到 “Package Dependencies” 部分出现了您的 MyCalculatorPackage

4.3 将 Package 产品链接到 Target

添加包依赖后,您还需要将包中提供的产品 (如 MyCalculatorPackage 库) 链接到您的应用程序 Target:

  1. 在项目导航器中,选择您的应用程序 Target。
  2. 选择 “General” 选项卡。
  3. 滚动到 “Frameworks, Libraries, and Embedded Content” 部分。
  4. 点击左下角的 “+” 按钮。
  5. 在列表中找到 MyCalculatorPackage (Library 类型),选择它,然后点击 “Add”。

现在,您的应用程序 Target 已经可以访问 MyCalculatorPackage 中定义的公开类型了。

4.4 在应用程序中使用 Package

在您的应用程序代码中 (例如 ViewController.swift),您可以导入并使用 Calculator 结构体:

“`swift
import UIKit
import MyCalculatorPackage // 导入您的 Swift Package 模块

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    let calculator = Calculator()
    let sum = calculator.add(10, 5)
    print("Sum: \(sum)") // 输出:Sum: 15

    if let divisionResult = calculator.divide(10, 2) {
        print("Division: \(divisionResult)") // 输出:Division: 5.0
    } else {
        print("Cannot divide by zero!")
    }
}

}
“`

运行您的应用程序,您将在控制台看到计算结果。

5. 高级主题 (简述)

  • 本地 Package 的开发: 您可以将本地 Package 拖拽到 Xcode 项目的同一工作空间 (.xcworkspace) 中进行并行开发。这样,对 Package 的修改会立即反映在应用程序中。
  • 二进制 Target: SPM 支持引入预编译的二进制框架 (.xcframework),这对于分发闭源库非常有用。
  • 版本管理: 在 Package.swift 文件中,可以使用 upToNextMajor(from: "1.0.0"), upToNextMinor(from: "1.0.0"), .exact("1.0.0") 等规则来指定依赖的版本范围。
  • Package Collections: Apple 和社区提供 Package Collections,可以方便地发现和添加可信赖的 Swift Packages。

6. 总结

Swift Package Manager 提供了一个强大、原生且易于使用的工具,用于管理 Swift 项目中的依赖。通过本文的引导,您应该已经能够从零开始创建一个 Swift Package,并成功将其集成到您的 Xcode 项目中。SPM 极大地简化了 Swift 代码的模块化和分发,是现代 Swift 开发不可或缺的一部分。


滚动至顶部