SPM (Swift Package Manager) — вбудований менеджер пакетів екосистеми Swift, розроблений Apple для автоматизації підключення, збірки та оновлення сторонніх бібліотек. SPM входить до складу компілятора Swift починаючи з версії 3.0 (2016 рік) і не потребує окремого встановлення. На відміну від CocoaPods та Carthage, SPM інтегрований безпосередньо з компілятором та Xcode, що робить його стандартним інструментом керування залежностями в сучасних Swift-проектах. У статті розберемо влаштування Package.swift, команди 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.
SPM побудований навколо трьох ключових концепцій: пакети (packages), продукти (products) та цілі (targets). Пакет — це Git-репозиторій з маніфестом Package.swift. Продукт — результат збірки (бібліотека або виконуваний файл). Ціль — модуль усередині пакета, який компілюється в одиницю збірки.
Коли розробник додає залежність у Package.swift, SPM виконує наступні кроки:
~Library/Caches/org.swift.swiftpm/.Файл Package.resolved фіксує точні версії всіх залежностей, щоб команда розробників працювала з ідентичним набором бібліотек. Цей файл має бути доданий до системи контролю версій (git).
Ключова перевага SPM перед аналогами — відсутність централізованого реєстру. Пакети можуть розташовуватися в будь-якому публічному Git-репозиторії: GitHub, GitLab, Bitbucket, а також на власних Git-серверах компанії. З версії Swift 5.2 SPM підтримує двійкові залежності (binary targets) — закриті бібліотеки, що поширюються через XCFramework без надання вихідного коду.
Package.swift — це Swift-файл, який описує структуру пакета та його залежності. Файл пишеться на самому Swift (не JSON, не YAML), що дає можливість використовувати умовну логіку, обчислювані константи та функції всередині маніфесту.
Базова структура Package.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/).Приклад вказівки точної версії, гілки та коміту:
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, що дозволяє точніше налаштовувати лінкування для статичних та динамічних бібліотек.
Swift Package Manager надає набір команд для роботи через термінал. Команди запускаються з кореневої директорії пакета (там, де лежить Package.swift).
# Створити новий пакет з бібліотекою
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 бібліотек. Розглянемо покроковий процес.
mkdir MyNetworkKit
cd MyNetworkKit
swift package init --type library
Команда swift package init створює наступну структуру:
MyNetworkKit/
├── Package.swift
├── README.md
├── Sources/
│ └── MyNetworkKit/
│ └── MyNetworkKit.swift
└── Tests/
└── MyNetworkKitTests/
└── MyNetworkKitTests.swift
SPM автоматично сканує директорії Sources/ та Tests/: кожна піддиректорія всередині Sources відповідає цілі (target).
Додамо залежності та налаштуємо цільові платформи:
// 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"]
),
]
)
// 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
}
}
Запуште пакет у Git-репозиторій та створіть SemVer-тег:
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").
Alamofire — найпопулярніший HTTP-клієнт для Swift. Додамо його через SPM та виконаємо GET-запит.
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)")
}
}
}
Бібліотека Swinject надає DI-контейнер для Swift. Підключається через .package(url: "https://github.com/Swinject/Swinject.git", from: "2.8.0").
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()
Пакет swift-log від Apple — єдиний API логування, що підтримує безліч бекендів (OSLog, консоль, файли).
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, міграція на SPM виконується в кілька кроків. Процес безпечний: SPM-залежності можуть співіснувати з CocoaPods та Carthage в одному проекті, що дозволяє мігрувати поступово.
.xcworkspace, відкрийте .xcodeproj та виконайте Clean Build Folder.rm -rf Carthage/ у терміналі.На момент 2025 року SPM підтримує переважну більшість популярних Swift-бібліотек. Винятки становлять деякі ObjC-фреймворки без модульних карт (modulemap). Якщо бібліотека ще не підтримує SPM — перевірте розділ Installation в її README; більшість авторів вже додали підтримку SPM в останніх версіях.
Часті запитання
SPM вбудований у компілятор Swift та Xcode, не потребує встановлення через gem або Homebrew. CocoaPods використовує централізований реєстр Specs та генерує окремий workspace. Carthage працює через фреймворки без інтеграції з проектом. SPM — єдиний менеджер, інтегрований на рівні компілятора: залежності вирішуються, кешуються та збираються паралельно з основним кодом.
Так, SPM підтримує змішані проекти Swift + Objective-C. ObjC-файли всередині SPM-пакета автоматично потрапляють в Umbrella Header за умови коректного modulemap. Однак SPM не підтримує статичні бібліотеки ObjC, що не мають модульної карти. Рекомендується підключати ObjC-бібліотеки через SPM тільки якщо вони надають modulemap або написані на чистому C.
SPM використовує семантичне версіонування (SemVer). Якщо пакет A потребує Alamofire 5.8+, а пакет B — Alamofire 5.9+, SPM обере версію 5.9.x, що задовольняє обидва. Якщо конфлікт нерозв'язний (один пакет потребує 5.x, інший — 6.x), SPM повідомить про помилку. У такому випадку необхідно оновити один із пакетів або переключити залежність на версію, сумісну з обома вимогами.
На macOS: ~Library/Caches/org.swift.swiftpm/ та ~/Library/Developer/Xcode/DerivedData/. На Linux: ~cache/swiftpm/. При збірці SPM кешує вихідний код та скомпільовані об'єктні файли. Для повної очистки кешу виконайте swift package reset — ця команда видаляє кеш залежностей та DerivedData для поточного проекту.
Так, починаючи з Swift 5.2 SPM підтримує двійкові цілі (binary targets). Закрита бібліотека постачається як XCFramework, а в Package.swift вказується шлях до .xcframework. Вихідний код при цьому не розкривається. Binary target вказується через .binaryTarget(name: "PrivateSDK", path: "Sources/PrivateSDK.xcframework"). Це дозволяє підключати комерційні SDK, не порушуючи ліцензійних угод.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.