SPM (Swift Package Manager) — de ingebouwde pakketbeheerder van het Swift-ecosysteem, ontwikkeld door Apple voor het automatiseren van het aansluiten, bouwen en updaten van bibliotheken van derden. SPM maakt deel uit van de Swift-compiler sinds versie 3.0 (2016) en vereist geen aparte installatie. In tegenstelling tot CocoaPods en Carthage is SPM direct geïntegreerd met de compiler en Xcode, waardoor het de standaard tool is voor afhankelijkheidsbeheer in moderne Swift-projecten. In dit artikel bespreken we de structuur van Package.swift, SPM-commando's, het schrijven van eigen pakketten en migratie van alternatieve beheerders.
Belangrijkste punten
SPM (Swift Package Manager) — de officiële pakketbeheerder voor de programmeertaal Swift, ingebouwd in de swiftc-compiler en de Xcode-ontwikkelomgeving. Het stelt ontwikkelaars in staat om bibliotheken van derden aan te sluiten, hun versies te beheren en eigen pakketten te publiceren. SPM verscheen voor het eerst in Swift 3.0 (september 2016) als commandoregel-tool en kreeg vanaf Xcode 11 (2019) volledige integratie met de grafische interface — nu worden afhankelijkheden toegevoegd via het menu File → Add Packages.
SPM downloadt automatisch de broncode van afhankelijkheden uit Git-repository's, bouwt ze parallel met het hoofdproject en cachet de resultaten zodat herbouwen sneller gaan. In tegenstelling tot CocoaPods genereert SPM geen aparte workspace (xcworkspace) — afhankelijkheden worden onderdeel van het hoofd Xcode-project. Volgens de Swift.org Developer Survey (2024) gebruikt 67% van de iOS-ontwikkelaars SPM, wat het de populairste tool voor afhankelijkheidsbeheer in het Swift-ecosysteem maakt.
SPM ondersteunt drie platformen: Apple (iOS, macOS, tvOS, watchOS, visionOS), Linux (Ubuntu, CentOS, Amazon Linux) en server-Swift (Vapor, Kitura). Op Linux werkt SPM volledig via de commandoregel zonder Xcode.
SPM is gebouwd rond drie kernconcepten: pakketten (packages), producten (products) en doelen (targets). Een pakket is een Git-repository met het manifest Package.swift. Een product is het bouwresultaat (bibliotheek of uitvoerbaar bestand). Een doel is een module binnen het pakket die tot een bouweenheid wordt gecompileerd.
Wanneer een ontwikkelaar een afhankelijkheid toevoegt in Package.swift, voert SPM de volgende stappen uit:
~Library/Caches/org.swift.swiftpm/.Het bestand Package.resolved legt de exacte versies van alle afhankelijkheden vast, zodat het ontwikkelteam met dezelfde set bibliotheken werkt. Dit bestand moet aan het versiebeheersysteem (git) worden toegevoegd.
Het belangrijkste voordeel van SPM ten opzichte van alternatieven — geen gecentraliseerd register. Pakketten kunnen in elke openbare Git-repository staan: GitHub, GitLab, Bitbucket, en ook op de eigen Git-servers van het bedrijf. Sinds Swift 5.2 ondersteunt SPM binaire afhankelijkheden (binary targets) — gesloten bibliotheken die via XCFramework worden gedistribueerd zonder broncode vrij te geven.
Package.swift — is een Swift-bestand dat de structuur van het pakket en zijn afhankelijkheden beschrijft. Het bestand wordt in Swift zelf geschreven (niet JSON, niet YAML), wat het mogelijk maakt om voorwaardelijke logica, berekende constanten en functies binnen het manifest te gebruiken.
Basisstructuur van 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"]
),
]
)
Laten we de belangrijkste elementen bekijken:
// swift-tools-version: 5.9 — directive die de SPM-versie aangeeft; de beschikbare syntax van het manifest hangt hiervan af.name — de pakketnaam, weergegeven in Xcode en gebruikt in afhankelijkheidsverwijzingen.platforms — minimale versies van platformen; SPM staat niet toe het pakket te bouwen op een oudere OS-versie.products — wat het pakket "exporteert": bibliotheek (.library) of uitvoerbaar bestand (.executable).dependencies — lijst van externe pakketten met URL en versie; from:, exact:, branch:, revision: worden ondersteund.targets — build-doelen; elk doel bevat een lijst van afhankelijkheden, bronnen en swift-bestanden uit de bijbehorende map (Sources/TargetName/).Voorbeeld van het specificeren van exacte versie, branch en commit:
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"),
]
Sinds Swift 5.9 is ondersteuning voor static/framework en linkerSettings toegevoegd aan Package.swift, wat nauwkeurigere configuratie van het linken voor statische en dynamische bibliotheken mogelijk maakt.
Swift Package Manager biedt een reeks commando's voor gebruik via de terminal. Commando's worden uitgevoerd vanuit de hoofdmap van het pakket (waar Package.swift zich bevindt).
# Nieuw pakket met bibliotheek maken
swift package init --type library
# Uitvoerbaar pakket maken (console-applicatie)
swift package init --type executable
# Project bouwen
swift build
# Bouwen in release-configuratie
swift build -c release
# Tests uitvoeren
swift test
# Specifieke test uitvoeren
swift test --filter "MyLibraryTests/testExample"
# Afhankelijkheden downloaden en oplossen
swift package resolve
# Afhankelijkheden bijwerken naar nieuwste beschikbare versies
swift package update
# Afhankelijkheidsgraaf tonen
swift package show-dependencies
# Build-cache opschonen
swift package clean
# Xcode-project genereren (vóór Xcode 11)
swift package generate-xcodeproj
Bij het werken in Xcode worden de meeste van deze commando's automatisch uitgevoerd: afhankelijkheden worden opgelost bij het openen van het project, bouwen wordt gestart met ⌘B, tests met ⌘U. Kennis van terminalcommando's is echter noodzakelijk voor CI/CD-pijplijnen (GitHub Actions, GitLab CI, Jenkins), waar Xcode niet beschikbaar is.
Het commando swift package resolve maakt of werkt het bestand Package.resolved bij. Dit bestand legt de exacte versies van alle afhankelijkheden vast, inclusief transitieve, en moet aan git worden toegevoegd. Het wordt aanbevolen om swift package update uit te voeren vóór elke nieuwe feature-branch, om met de huidige versies van bibliotheken te werken.
Het maken van een eigen SPM-pakket is nuttig voor het inkapselen van bedrijfslogica in multimodule-projecten en voor het publiceren van open-source bibliotheken. Laten we het stapsgewijze proces bekijken.
mkdir MyNetworkKit
cd MyNetworkKit
swift package init --type library
Het commando swift package init maakt de volgende structuur:
MyNetworkKit/
├── Package.swift
├── README.md
├── Sources/
│ └── MyNetworkKit/
│ └── MyNetworkKit.swift
└── Tests/
└── MyNetworkKitTests/
└── MyNetworkKitTests.swift
SPM scant automatisch de mappen Sources/ en Tests/: elke submap binnen Sources komt overeen met een doel (target).
We voegen afhankelijkheden toe en configureren de doelplatformen:
// 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
}
}
Push het pakket naar de Git-repository en maak een SemVer-tag:
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
Hierna kan elke ontwikkelaar uw pakket aansluiten via .package(url: "https://github.com/username/MyNetworkKit.git", from: "1.0.0").
Alamofire — de populairste HTTP-client voor Swift. We voegen het toe via SPM en voeren een GET-verzoek uit.
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) gebruikers ontvangen")
case .failure(let error):
print("Fout: \(error.localizedDescription)")
}
}
}
De Swinject-bibliotheek biedt een DI-container voor Swift. Verbonden via .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()
Het swift-log pakket van Apple — een uniforme logging-API die meerdere back-ends ondersteunt (OSLog, console, bestanden).
import Logging
var logger = Logger(label: "com.myapp.network")
logger.logLevel = .debug
logger.info("Netwerkverzoek gestart", metadata: [
"url": "\(requestURL)",
"method": "GET"
])
logger.warning("Reactietijd overschreed 2 seconden")
logger.error("Verbindingsfout: geen internet")
Deze drie voorbeelden dekken typische SPM-gebruiksscenario's: HTTP-cliënten, DI-containers en systeeminfrastructuur. De keuze van bibliotheken is niet toevallig — Alamofire, Swinject en swift-log behoren tot de top 20 meest populaire Swift-pakketten op GitHub.
Als het project CocoaPods of Carthage gebruikt, wordt de migratie naar SPM in enkele stappen uitgevoerd. Het proces is veilig: SPM-afhankelijkheden kunnen samen met CocoaPods en Carthage in één project bestaan, wat gefaseerde migratie mogelijk maakt.
.xcworkspace, open .xcodeproj en voer Clean Build Folder uit.rm -rf Carthage/ in de terminal.Vanaf 2025 ondersteunt SPM de overgrote meerderheid van populaire Swift-bibliotheken. Uitzonderingen zijn sommige ObjC-frameworks zonder modulemaps (modulemap). Als een bibliotheek SPM nog niet ondersteunt — controleer de sectie Installation in de README; de meeste auteurs hebben SPM-ondersteuning al toegevoegd in de nieuwste versies.
Veelgestelde vragen
SPM is ingebouwd in de Swift-compiler en Xcode, vereist geen installatie via gem of Homebrew. CocoaPods gebruikt een gecentraliseerd Specs-register en genereert een aparte workspace. Carthage werkt via frameworks zonder integratie met het project. SPM is de enige beheerder die op compilerniveau is geïntegreerd: afhankelijkheden worden opgelost, gecachet en parallel met de hoofdcode gebouwd.
Ja, SPM ondersteunt gemengde Swift + Objective-C-projecten. ObjC-bestanden binnen een SPM-pakket komen automatisch in de Umbrella Header terecht, op voorwaarde van een correcte modulemap. SPM ondersteunt echter geen statische ObjC-bibliotheken zonder modulemap. Het wordt aanbevolen om ObjC-bibliotheken via SPM alleen aan te sluiten als ze een modulemap bieden of in puur C zijn geschreven.
SPM gebruikt semantische versiebeheer (SemVer). Als pakket A Alamofire 5.8+ nodig heeft en pakket B Alamofire 5.9+, kiest SPM versie 5.9.x die aan beide voldoet. Als het conflict onoplosbaar is (het ene pakket heeft 5.x nodig, het andere 6.x), meldt SPM een fout. In dat geval moet u een van de pakketten bijwerken of de afhankelijkheid wijzigen naar een versie die compatibel is met beide vereisten.
Op macOS: ~Library/Caches/org.swift.swiftpm/ en ~/Library/Developer/Xcode/DerivedData/. Op Linux: ~cache/swiftpm/. Tijdens het bouwen cachet SPM de broncode en gecompileerde objectbestanden. Voor het volledig opschonen van de cache voert u swift package reset uit — dit commando verwijdert de afhankelijkheidscache en DerivedData voor het huidige project.
Ja, sinds Swift 5.2 ondersteunt SPM binaire doelen (binary targets). Een gesloten bibliotheek wordt geleverd als XCFramework, en in Package.swift wordt het pad naar het .xcframework opgegeven. De broncode wordt niet onthuld. Binary target wordt gespecificeerd via .binaryTarget(name: "PrivateSDK", path: "Sources/PrivateSDK.xcframework"). Dit maakt het mogelijk om commerciële SDK's aan te sluiten zonder licentieovereenkomsten te schenden.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook