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
# Изгради у release конфигурацији
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. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође