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, консоль, файли).

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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

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