SPM (Swift Package Manager) — managerul de pachete încorporat al ecosistemului Swift, dezvoltat de Apple pentru automatizarea conectării, construirii și actualizării bibliotecilor terțe. SPM face parte din compilatorul Swift începând cu versiunea 3.0 (2016) și nu necesită instalare separată. Spre deosebire de CocoaPods și Carthage, SPM este integrat direct cu compilatorul și Xcode, ceea ce îl face instrumentul standard de gestionare a dependențelor în proiectele Swift moderne. În articol vom analiza structura Package.swift, comenzile SPM, scrierea propriilor pachete și migrarea de la managerii alternativi.
Principalele puncte
SPM (Swift Package Manager) — managerul oficial de pachete pentru limbajul Swift, încorporat în compilatorul swiftc și mediul de dezvoltare Xcode. Acesta permite dezvoltatorilor să conecteze biblioteci terțe, să gestioneze versiunile acestora și să publice propriile pachete. SPM a apărut pentru prima dată în Swift 3.0 (septembrie 2016) ca instrument de linie de comandă, iar începând cu Xcode 11 (2019) a primit integrare completă cu interfața grafică — acum dependențele se adaugă prin meniul File → Add Packages.
SPM descarcă automat codul sursă al dependențelor din depozitele Git, le construiește în paralel cu proiectul principal și stochează în cache rezultatele pentru ca recompilările să fie mai rapide. Spre deosebire de CocoaPods, SPM nu generează un workspace separat (xcworkspace) — dependențele devin parte a proiectului principal Xcode. Conform sondajului Swift.org Developer Survey (2024), SPM este utilizat de 67% dintre dezvoltatorii iOS, ceea ce îl face cel mai popular instrument de gestionare a dependențelor în ecosistemul Swift.
SPM suportă trei platforme: Apple (iOS, macOS, tvOS, watchOS, visionOS), Linux (Ubuntu, CentOS, Amazon Linux) și Swift server (Vapor, Kitura). Pe Linux, SPM funcționează complet prin linie de comandă fără Xcode.
SPM este construit în jurul a trei concepte cheie: pachete (packages), produse (products) și ținte (targets). Un pachet este un depozit Git cu manifestul Package.swift. Un produs este rezultatul compilării (bibliotecă sau fișier executabil). O țintă este un modul în cadrul pachetului care se compilează într-o unitate de construcție.
Când un dezvoltator adaugă o dependență în Package.swift, SPM execută următorii pași:
~Library/Caches/org.swift.swiftpm/.Fișierul Package.resolved fixează versiunile exacte ale tuturor dependențelor, astfel încât echipa de dezvoltare să lucreze cu același set de biblioteci. Acest fișier trebuie adăugat în sistemul de control al versiunilor (git).
Avantajul cheie al SPM față de alternative — absența unui registru centralizat. Pachetele pot fi localizate în orice depozit Git public: GitHub, GitLab, Bitbucket, precum și pe serverele Git proprii ale companiei. Începând cu Swift 5.2, SPM suportă dependențe binare (binary targets) — biblioteci închise distribuite prin XCFramework fără a furniza codul sursă.
Package.swift — este un fișier Swift care descrie structura pachetului și dependențele sale. Fișierul este scris în Swift însuși (nu JSON, nu YAML), ceea ce permite utilizarea logicii condiționale, constantelor calculate și funcțiilor în interiorul manifestului.
Structura de bază a 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"]
),
]
)
Să analizăm elementele cheie:
// swift-tools-version: 5.9 — directivă care indică versiunea SPM; de ea depinde sintaxa disponibilă a manifestului.name — numele pachetului, afișat în Xcode și utilizat în referințele de dependențe.platforms — versiunile minime ale platformelor; SPM nu va permite construirea pachetului pe o versiune mai veche de OS.products — ceea ce „exportă" pachetul: bibliotecă (.library) sau fișier executabil (.executable).dependencies — lista pachetelor externe cu URL și versiune; sunt suportate from:, exact:, branch:, revision:.targets — ținte de compilare; fiecare țintă conține lista de dependențe, resurse și fișiere swift din directorul corespunzător (Sources/TargetName/).Exemplu de specificare a versiunii exacte, ramurii și commit-ului:
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"),
]
Începând cu Swift 5.9, în Package.swift a fost adăugat suportul pentru static/framework și linkerSettings, ceea ce permite configurarea mai precisă a legăturii pentru bibliotecile statice și dinamice.
Swift Package Manager oferă un set de comenzi pentru lucrul prin terminal. Comenzile se rulează din directorul rădăcină al pachetului (unde se află Package.swift).
# Creează un pachet nou cu bibliotecă
swift package init --type library
# Creează un pachet executabil (aplicație consolă)
swift package init --type executable
# Construiește proiectul
swift build
# Construiește în configurația release
swift build -c release
# Rulează testele
swift test
# Rulează un test specific
swift test --filter "MyLibraryTests/testExample"
# Descarcă și rezolvă dependențele
swift package resolve
# Actualizează dependențele la cele mai recente versiuni disponibile
swift package update
# Arată graful de dependențe
swift package show-dependencies
# Curăță cache-ul de compilare
swift package clean
# Generează proiect Xcode (înainte de Xcode 11)
swift package generate-xcodeproj
În timpul lucrului în Xcode, majoritatea acestor comenzi se execută automat: dependențele sunt rezolvate la deschiderea proiectului, compilarea se rulează cu ⌘B, testele cu ⌘U. Cu toate acestea, cunoașterea comenzilor de terminal este necesară pentru pipeline-urile CI/CD (GitHub Actions, GitLab CI, Jenkins), unde Xcode nu este disponibil.
Comanda swift package resolve creează sau actualizează fișierul Package.resolved. Acest fișier fixează versiunile exacte ale tuturor dependențelor, inclusiv pe cele tranzitive, și trebuie adăugat în git. Se recomandă rularea swift package update înainte de fiecare ramură feature nouă, pentru a lucra cu versiunile actuale ale bibliotecilor.
Crearea propriului pachet SPM este utilă pentru încapsularea logicii de business în proiecte multi-modul și pentru publicarea bibliotecilor open-source. Să analizăm procesul pas cu pas.
mkdir MyNetworkKit
cd MyNetworkKit
swift package init --type library
Comanda swift package init creează următoarea structură:
MyNetworkKit/
├── Package.swift
├── README.md
├── Sources/
│ └── MyNetworkKit/
│ └── MyNetworkKit.swift
└── Tests/
└── MyNetworkKitTests/
└── MyNetworkKitTests.swift
SPM scanează automat directoarele Sources/ și Tests/: fiecare subdirector din Sources corespunde unei ținte (target).
Adăugăm dependențe și configurăm platformele țintă:
// 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
}
}
Împingeți pachetul în depozitul Git și creați un tag 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
După aceasta, orice dezvoltator va putea conecta pachetul dvs. prin .package(url: "https://github.com/username/MyNetworkKit.git", from: "1.0.0").
Alamofire — cel mai popular client HTTP pentru Swift. Îl vom adăuga prin SPM și vom executa o cerere 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("S-au primit \(users.count) utilizatori")
case .failure(let error):
print("Eroare: \(error.localizedDescription)")
}
}
}
Biblioteca Swinject oferă un container DI pentru Swift. Se conectează prin .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()
Pachetul swift-log de la Apple — o API unificată de logare care suportă multiple backend-uri (OSLog, consolă, fișiere).
import Logging
var logger = Logger(label: "com.myapp.network")
logger.logLevel = .debug
logger.info("Cerere de rețea începută", metadata: [
"url": "\(requestURL)",
"method": "GET"
])
logger.warning("Timpul de răspuns a depășit 2 secunde")
logger.error("Eroare de conexiune: fără internet")
Aceste trei exemple acoperă scenariile tipice de utilizare SPM: clienți HTTP, containere DI și infrastructură de sistem. Alegerea bibliotecilor nu este întâmplătoare — Alamofire, Swinject și swift-log se află în top 20 cele mai populare pachete Swift pe GitHub.
Dacă proiectul utilizează CocoaPods sau Carthage, migrarea la SPM se face în câțiva pași. Procesul este sigur: dependențele SPM pot coexista cu CocoaPods și Carthage în același proiect, permițând migrarea treptată.
.xcworkspace, deschideți .xcodeproj și executați Clean Build Folder.rm -rf Carthage/ în terminal.În 2025, SPM suportă marea majoritate a bibliotecilor populare Swift. Excepțiile sunt unele framework-uri ObjC fără hărți de module (modulemap). Dacă o bibliotecă nu suportă încă SPM — verificați secțiunea Installation din README-ul său; majoritatea autorilor au adăugat deja suport SPM în cele mai recente versiuni.
Întrebări frecvente
SPM este încorporat în compilatorul Swift și Xcode, nu necesită instalare prin gem sau Homebrew. CocoaPods utilizează un registru centralizat Specs și generează un workspace separat. Carthage funcționează prin framework-uri fără integrare în proiect. SPM este singurul manager integrat la nivel de compilator: dependențele sunt rezolvate, stocate în cache și construite în paralel cu codul principal.
Da, SPM suportă proiecte mixte Swift + Objective-C. Fișierele ObjC din cadrul pachetului SPM ajung automat în Umbrella Header cu condiția unui modulemap corect. Cu toate acestea, SPM nu suportă biblioteci statice ObjC care nu au o mapă de module. Se recomandă conectarea bibliotecilor ObjC prin SPM doar dacă acestea furnizează modulemap sau sunt scrise în C pur.
SPM utilizează versionarea semantică (SemVer). Dacă pachetul A necesită Alamofire 5.8+, iar pachetul B — Alamofire 5.9+, SPM va selecta versiunea 5.9.x care satisface ambele cerințe. Dacă conflictul este de nerezolvat (un pachet necesită 5.x, altul — 6.x), SPM va raporta o eroare. În acest caz, trebuie să actualizați unul dintre pachete sau să schimbați dependența la o versiune compatibilă cu ambele cerințe.
Pe macOS: ~Library/Caches/org.swift.swiftpm/ și ~/Library/Developer/Xcode/DerivedData/. Pe Linux: ~cache/swiftpm/. În timpul compilării, SPM stochează în cache codul sursă și fișierele obiect compilate. Pentru a curăța complet cache-ul, executați swift package reset — această comandă șterge cache-ul dependențelor și DerivedData pentru proiectul curent.
Da, începând cu Swift 5.2, SPM suportă ținte binare (binary targets). Biblioteca închisă este furnizată ca XCFramework, iar în Package.swift se indică calea către .xcframework. Codul sursă nu este dezvăluit. Binary target se specifică prin .binaryTarget(name: "PrivateSDK", path: "Sources/PrivateSDK.xcframework"). Acest lucru permite conectarea SDK-urilor comerciale fără a încălca acordurile de licență.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și