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 δεν δημιουργεί ξεχωριστό χώρο εργασίας (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 με manifest 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), γεγονός που επιτρέπει τη χρήση υπό όρων λογικής, υπολογιζόμενων σταθερών και συναρτήσεων εντός του manifest.
Βασική δομή του 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; η διαθέσιμη σύνταξη του manifest εξαρτάται από αυτήν.name — το όνομα του πακέτου, που εμφανίζεται στο Xcode και χρησιμοποιείται σε αναφορές εξαρτήσεων.platforms — ελάχιστες εκδόσεις πλατφορμών; το SPM δεν θα επιτρέψει τη δημιουργία του πακέτου σε παλαιότερη έκδοση OS.products — τι "εξάγει" το πακέτο: βιβλιοθήκη (.library) ή εκτελέσιμο αρχείο (.executable).dependencies — λίστα εξωτερικών πακέτων με URL και έκδοση; υποστηρίζονται from:, exact:, branch:, revision:.targets — στόχοι δημιουργίας; κάθε στόχος περιέχει λίστα εξαρτήσεων, πόρων και αρχείων swift από τον αντίστοιχο κατάλογο (Sources/TargetName/).Παράδειγμα καθορισμού ακριβούς έκδοσης, κλάδου και 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"),
]
Από την έκδοση Swift 5.9, προστέθηκε υποστήριξη για static/framework και linkerSettings στο Package.swift, επιτρέποντας ακριβέστερη ρύθμιση σύνδεσης για στατικές και δυναμικές βιβλιοθήκες.
Το 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 πριν από κάθε νέο κλάδο λειτουργίας, για να εργάζεστε με τις τρέχουσες εκδόσεις βιβλιοθηκών.
Η δημιουργία δικού σας πακέτου SPM είναι χρήσιμη για την ενθυλάκωση επιχειρηματικής λογικής σε πολυαρθρωτικά έργα και για τη δημοσίευση βιβλιοθηκών ανοιχτού κώδικα. Ας δούμε τη διαδικασία βήμα προς βήμα.
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 καταγραφής που υποστηρίζει πολλαπλά backend (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 και δημιουργούν ξεχωριστό χώρο εργασίας. Το 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. Ο πηγαίος κώδικας δεν αποκαλύπτεται. Ο δυαδικός στόχος καθορίζεται μέσω .binaryTarget(name: "PrivateSDK", path: "Sources/PrivateSDK.xcframework"). Αυτό επιτρέπει τη σύνδεση εμπορικών SDK χωρίς παραβίαση συμφωνιών άδειας χρήσης.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης