SPM: что это такое, Swift Package Manager и Package.swift

Автор: IT Sectr Опубликовано: 2026-02-13 Время чтения: 11 мин

SPM (Swift Package Manager) — встроенный менеджер пакетов экосистемы Swift, разработанный Apple для автоматизации подключения, сборки и обновления сторонних библиотек. SPM входит в состав компилятора Swift начиная с версии 3.0 (2016 год) и не требует отдельной установки. В отличие от CocoaPods и Carthage, SPM интегрирован напрямую с компилятором и Xcode, что делает его стандартным инструментом управления зависимостями в современных Swift-проектах. В статье разберём устройство Package.swift, команды SPM, написание собственных пакетов и миграцию с альтернативных менеджеров.

Главное

  • SPM (Swift Package Manager) — встроенный в компилятор Swift менеджер пакетов, не требующий отдельной установки; работает на iOS, macOS, Linux и серверных платформах.
  • Package.swift — манифест-файл, описывающий имя пакета, платформы, зависимости и целевые модули (targets) в декларативном формате.
  • SPM разрешает зависимости по семантическому версионированию (SemVer), кеширует исходный код и собирает пакеты параллельно для ускорения.
  • Команды: swift package init (создать пакет), swift package update (обновить зависимости), swift build (собрать), swift test (запустить тесты).
  • Миграция с CocoaPods/Carthage на SPM выполняется через Xcode: File → Add Package Dependency, после чего podfile и Cartfile удаляются.

Что такое SPM?

SPM (Swift Package Manager) — официальный менеджер пакетов для языка Swift, встроенный в компилятор swiftc и среду разработки Xcode. Он позволяет разработчикам подключать сторонние библиотеки, управлять их версиями и публиковать собственные пакеты. SPM впервые появился в Swift 3.0 (сентябрь 2016) как инструмент командной строки, а начиная с Xcode 11 (2019) получил полную интеграцию с графическим интерфейсом — теперь зависимости добавляются через меню File → Add Packages.

SPM автоматически загружает исходный код зависимостей из Git-репозиториев, собирает их параллельно с основным проектом и кеширует результаты, чтобы повторные сборки выполнялись быстрее. В отличие от CocoaPods, SPM не генерирует отдельный workspace (xcworkspace) — зависимости становятся частью основного проекта Xcode. По данным опроса Swift.org Developer Survey (2024), SPM используют 67% iOS-разработчиков, что делает его самым популярным инструментом управления зависимостями в Swift-экосистеме.

SPM поддерживает три платформы: Apple (iOS, macOS, tvOS, watchOS, visionOS), Linux (Ubuntu, CentOS, Amazon Linux) и серверный Swift (Vapor, Kitura). На Linux SPM работает полностью через командную строку без Xcode.

Как работает Swift Package Manager

SPM построен вокруг трёх ключевых концепций: пакеты (packages), продукты (products) и цели (targets). Пакет — это Git-репозиторий с манифестом Package.swift. Продукт — результат сборки (библиотека или исполняемый файл). Цель — модуль внутри пакета, который компилируется в единицу сборки.

Когда разработчик добавляет зависимость в Package.swift, SPM выполняет следующие шаги:

  1. Клонирование — SPM скачивает Git-репозиторий зависимости по указанному URL.
  2. Разрешение версий — анализирует теги SemVer (например, 2.1.3) и выбирает подходящую версию в пределах указанного диапазона.
  3. Транзитивное разрешение — проверяет зависимости зависимостей и строит граф без конфликтов версий.
  4. Кеширование — сохраняет скачанный исходный код в ~Library/Caches/org.swift.swiftpm/.
  5. Компиляция — собирает все цели пакета с флагами основного проекта.

Файл Package.resolved фиксирует точные версии всех зависимостей, чтобы команда разработчиков работала с идентичным набором библиотек. Этот файл должен быть добавлен в систему контроля версий (git).

Ключевое преимущество SPM перед аналогами — отсутствие централизованного реестра. Пакеты могут располагаться в любом публичном Git-репозитории: GitHub, GitLab, Bitbucket, а также на собственных Git-серверах компании. С версии Swift 5.2 SPM поддерживает двоичные зависимости (binary targets) — закрытые библиотеки, распространяемые через XCFramework без предоставления исходного кода.

Package.swift — манифест проекта

Package.swift — это Swift-файл, который описывает структуру пакета и его зависимости. Файл пишется на самом Swift (не JSON, не YAML), что даёт возможность использовать условную логику, вычисляемые константы и функции внутри манифеста.

Базовая структура Package.swift:

swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "MyLibrary",
    platforms: [
        .iOS(.v16),
        .macOS(.v13)
    ],
    products: [
        .library(
            name: "MyLibrary",
            targets: ["MyLibrary"]
        ),
    ],
    dependencies: [
        .package(url: "https://github.com/Alamofire/Alamofire.git",
                 from: "5.9.0"),
        .package(url: "https://github.com/onevcat/Kingfisher.git",
                 from: "7.12.0"),
    ],
    targets: [
        .target(
            name: "MyLibrary",
            dependencies: [
                "Alamofire",
                "Kingfisher"
            ]
        ),
        .testTarget(
            name: "MyLibraryTests",
            dependencies: ["MyLibrary"]
        ),
    ]
)

Разберём ключевые элементы:

  • // swift-tools-version: 5.9 — директива, указывающая версию SPM; от неё зависит доступный синтаксис манифеста.
  • name — имя пакета, отображаемое в Xcode и используемое в ссылках зависимостей.
  • platforms — минимальные версии платформ; SPM не позволит собрать пакет на более старой версии ОС.
  • products — что «экспортирует» пакет: библиотеку (.library) или исполняемый файл (.executable).
  • dependencies — список внешних пакетов с URL и версией; поддерживаются from:, exact:, branch:, revision:.
  • targets — цели сборки; каждая цель содержит список зависимостей, ресурсы и swift-файлы из соответствующей директории (Sources/TargetName/).

Пример указания точной версии, ветки и коммита:

swift
dependencies: [
    .package(url: "https://github.com/pointfreeco/swift-snapshot-testing.git",
             exact: "1.17.3"),
    .package(url: "https://github.com/pointfreeco/swift-composable-architecture.git",
             branch: "main"),
    .package(url: "https://github.com/apple/swift-log.git",
             revision: "e5c6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4"),
]

С версии Swift 5.9 в Package.swift добавлена поддержка static/framework и linkerSettings, что позволяет точнее настраивать линковку для статических и динамических библиотек.

Основные команды SPM

Swift Package Manager предоставляет набор команд для работы через терминал. Команды запускаются из корневой директории пакета (там, где лежит Package.swift).

bash
# Создать новый пакет с библиотекой
swift package init --type library

# Создать исполняемый пакет (консольное приложение)
swift package init --type executable

# Собрать проект
swift build

# Собрать в релизной конфигурации
swift build -c release

# Запустить тесты
swift test

# Запустить конкретный тест
swift test --filter "MyLibraryTests/testExample"

# Загрузить и разрешить зависимости
swift package resolve

# Обновить зависимости до последних доступных версий
swift package update

# Показать граф зависимостей
swift package show-dependencies

# Очистить кеш сборки
swift package clean

# Сгенерировать Xcode-проект (до Xcode 11)
swift package generate-xcodeproj

При работе внутри Xcode большинство этих команд выполняются автоматически: зависимости разрешаются при открытии проекта, сборка запускается по ⌘B, тесты — по ⌘U. Однако знание терминальных команд необходимо для CI/CD-пайплайнов (GitHub Actions, GitLab CI, Jenkins), где Xcode недоступен.

Команда swift package resolve создаёт или обновляет файл Package.resolved. Этот файл фиксирует точные версии всех зависимостей, включая транзитивные, и должен быть добавлен в git. Рекомендуется запускать swift package update перед каждой новой feature-веткой, чтобы работать с актуальными версиями библиотек.

Создание собственного пакета

Создание собственного SPM-пакета полезно для инкапсуляции бизнес-логики в многомодульных проектах и для публикации open-source библиотек. Рассмотрим пошаговый процесс.

Шаг 1: Инициализация

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

Шаг 2: Структура директорий

Команда swift package init создаёт следующую структуру:

text
MyNetworkKit/
├── Package.swift
├── README.md
├── Sources/
│   └── MyNetworkKit/
│       └── MyNetworkKit.swift
└── Tests/
    └── MyNetworkKitTests/
        └── MyNetworkKitTests.swift

SPM автоматически сканирует директории Sources/ и Tests/: каждая поддиректория внутри Sources соответствует цели (target).

Шаг 3: Редактирование Package.swift

Добавим зависимости и настроим целевые платформы:

swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "MyNetworkKit",
    platforms: [
        .iOS(.v15),
        .macOS(.v12)
    ],
    products: [
        .library(
            name: "MyNetworkKit",
            targets: ["MyNetworkKit"]
        ),
    ],
    dependencies: [
        .package(url: "https://github.com/Alamofire/Alamofire.git",
                 from: "5.9.0"),
    ],
    targets: [
        .target(
            name: "MyNetworkKit",
            dependencies: ["Alamofire"]
        ),
        .testTarget(
            name: "MyNetworkKitTests",
            dependencies: ["MyNetworkKit"]
        ),
    ]
)

Шаг 4: Написание кода

swift
// Sources/MyNetworkKit/MyNetworkKit.swift
import Foundation
import Alamofire

public struct NetworkClient {
    private let session: Session

    public init() {
        let configuration = URLSessionConfiguration.default
        configuration.timeoutIntervalForRequest = 30
        self.session = Session(configuration: configuration)
    }

    public func fetchData(from url: String) async throws -> Data {
        let response = try await session.request(url).serializingData().value
        return response
    }
}

Шаг 5: Публикация

Пушните пакет в Git-репозиторий и создайте SemVer-тег:

bash
git init
git add .
git commit -m "Initial commit: MyNetworkKit"
git remote add origin https://github.com/username/MyNetworkKit.git
git push -u origin main
git tag 1.0.0
git push --tags

После этого любой разработчик сможет подключить ваш пакет через .package(url: "https://github.com/username/MyNetworkKit.git", from: "1.0.0").

Примеры использования SPM

Пример 1: Подключение Alamofire для сетевых запросов

Alamofire — самый популярный HTTP-клиент для Swift. Добавим его через SPM и выполним GET-запрос.

swift
import Alamofire

func fetchUsers() {
    AF.request("https://jsonplaceholder.typicode.com/users")
        .validate()
        .responseDecodable(of: [User].self) { response in
            switch response.result {
            case .success(let users):
                print("Получено (users.count) пользователей")
            case .failure(let error):
                print("Ошибка: (error.localizedDescription)")
            }
        }
}

Пример 2: Swinject — внедрение зависимостей

Библиотека Swinject предоставляет DI-контейнер для Swift. Подключается через .package(url: "https://github.com/Swinject/Swinject.git", from: "2.8.0").

swift
import Swinject

let container = Container()
container.register(NetworkServiceProtocol.self) { _ in NetworkService() }
container.register(DataRepositoryProtocol.self) { r in
    DataRepository(networkService: r.resolve(NetworkServiceProtocol.self)!)
}

let repository = container.resolve(DataRepositoryProtocol.self)
repository?.loadData()

Пример 3: Swift-log для структурированного логирования

Пакет swift-log от Apple — единый API логирования, поддерживающий множество бэкендов (OSLog, console, файлы).

swift
import Logging

var logger = Logger(label: "com.myapp.network")
logger.logLevel = .debug

logger.info("Сетевой запрос начат", metadata: [
    "url": "(requestURL)",
    "method": "GET"
])

logger.warning("Время ответа превысило 2 секунды")
logger.error("Ошибка соединения: нет интернета")

Эти три примера покрывают типовые сценарии использования SPM: HTTP-клиенты, DI-контейнеры и системная инфраструктура. Выбор библиотек не случаен — Alamofire, Swinject и swift-log входят в топ-20 самых звёздных Swift-пакетов на GitHub.

Миграция с CocoaPods и Carthage

Если проект использует CocoaPods или Carthage, миграция на SPM выполняется в несколько шагов. Процесс безопасен: SPM-зависимости могут сосуществовать с CocoaPods и Carthage в одном проекте, что позволяет мигрировать постепенно.

CocoaPods → SPM

  1. В Xcode: File → Add Package Dependency, введите URL пакета.
  2. Выберите версию и добавьте пакет к нужным targets.
  3. После добавления всех зависимостей через SPM удалите строки из Podfile.
  4. Удалите .xcworkspace, откройте .xcodeproj и выполните Clean Build Folder.

Carthage → SPM

  1. Добавьте пакеты через Xcode File → Add Package Dependency.
  2. Удалите зависимости из Cartfile.
  3. Удалите сценарии сборки Carthage из Build Phases.
  4. Очистите кеш: rm -rf Carthage/ в терминале.

На момент 2025 года SPM поддерживает подавляющее большинство популярных Swift-библиотек. Исключения составляют некоторые ObjC-фреймворки без модульных карт (modulemap). Если библиотека ещё не поддерживает SPM — проверьте раздел Installation в её README; большинство авторов уже добавили поддержку SPM в последних версиях.

Часто задаваемые вопросы

Чем SPM отличается от CocoaPods и Carthage?

SPM встроен в компилятор Swift и Xcode, не требует установки через gem или Homebrew. CocoaPods использует централизованный реестр Specs и генерирует отдельный workspace. Carthage работает через фреймворки без интеграции с проектом. SPM — единственный менеджер, интегрированный на уровне компилятора: зависимости разрешаются, кешируются и собираются параллельно с основным кодом.

Можно ли использовать SPM для Objective-C проектов?

Да, SPM поддерживает смешанные проекты Swift + Objective-C. ObjC-файлы внутри SPM-пакета автоматически попадают в Umbrella Header при условии корректного modulemap. Однако SPM не поддерживает статические библиотеки ObjC, не имеющие модульной карты. Рекомендуется подключать ObjC-библиотеки через SPM только если они предоставляют modulemap или написаны на чистом C.

Как SPM разрешает конфликты версий?

SPM использует семантическое версионирование (SemVer). Если пакет A требует Alamofire 5.8+, а пакет B — Alamofire 5.9+, SPM выберет версию 5.9.x, удовлетворяющую обоим. Если конфликт неразрешим (один пакет требует 5.x, другой — 6.x), SPM сообщит об ошибке. В таком случае необходимо обновить один из пакетов или переключить зависимость на версию, совместимую с обоими требованиями.

Где хранятся скачанные SPM-пакеты?

На macOS: ~Library/Caches/org.swift.swiftpm/ и ~/Library/Developer/Xcode/DerivedData/. На Linux: ~cache/swiftpm/. При сборке SPM кеширует исходный код и скомпилированные объектные файлы. Для полной очистки кеша выполните swift package reset — эта команда удаляет кеш зависимостей и DerivedData для текущего проекта.

Поддерживает ли SPM закрытые (проприетарные) библиотеки?

Да, начиная с Swift 5.2 SPM поддерживает двоичные цели (binary targets). Закрытая библиотека поставляется как XCFramework, а в Package.swift указывается путь к .xcframework. Исходный код при этом не раскрывается. Binary target указывается через .binaryTarget(name: "PrivateSDK", path: "Sources/PrivateSDK.xcframework"). Это позволяет подключать коммерческие SDK, не нарушая лицензионных соглашений.

Итоги

  • SPM (Swift Package Manager) — встроенный менеджер пакетов Swift, который не требует отдельной установки и интегрирован с Xcode и компилятором.
  • Package.swift — декларативный манифест на языке Swift, описывающий имя пакета, платформы, зависимости, продукты и цели сборки.
  • SPM использует Git-репозитории в качестве источника пакетов и разрешает версии по SemVer, кешируя исходный код для ускорения повторных сборок.
  • Основные команды: swift package init (создать пакет), swift build (собрать), swift test (протестировать), swift package update (обновить зависимости).
  • Собственный пакет создаётся через swift package init, публикуется в Git и доступен другим проектам по URL с SemVer-тегом.
  • Миграция с CocoaPods/Carthage на SPM безопасна: зависимости могут сосуществовать, миграция выполняется через File → Add Package Dependency в Xcode.
  • SPM — стандарт управления зависимостями в Swift-экосистеме, используемый 67% iOS-разработчиков (Swift.org Developer Survey, 2024).

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также