SPM (Swift Package Manager) — ang built-in na package manager ng Swift ecosystem, na binuo ng Apple para i-automate ang pagkonekta, pag-build, at pag-update ng mga third-party na library. Ang SPM ay bahagi ng Swift compiler simula sa bersyon 3.0 (2016) at hindi nangangailangan ng hiwalay na pag-install. Hindi tulad ng CocoaPods at Carthage, ang SPM ay direktang isinama sa compiler at Xcode, na ginagawa itong karaniwang tool para sa pamamahala ng dependency sa mga modernong Swift project. Sa artikulong ito, tatalakayin natin ang istraktura ng Package.swift, mga SPM command, pagsulat ng sariling mga package, at migration mula sa mga alternatibong manager.
Mga pangunahing punto
SPM (Swift Package Manager) — ang opisyal na package manager para sa Swift language, na naka-embed sa swiftc compiler at Xcode development environment. Pinapayagan nito ang mga developer na kumonekta sa mga third-party na library, pamahalaan ang kanilang mga bersyon, at mag-publish ng sariling mga package. Unang lumitaw ang SPM sa Swift 3.0 (Setyembre 2016) bilang isang command-line tool, at simula sa Xcode 11 (2019) ay nakakuha ng buong integration sa graphical interface — ngayon ang mga dependency ay idinaragdag sa pamamagitan ng menu na File → Add Packages.
Awtomatikong dina-download ng SPM ang source code ng mga dependency mula sa mga Git repository, bina-build ang mga ito nang magkatulad sa pangunahing proyekto, at nag-cache ng mga resulta upang mas mabilis ang mga pag-rebuild. Hindi tulad ng CocoaPods, hindi gumagawa ang SPM ng hiwalay na workspace (xcworkspace) — ang mga dependency ay nagiging bahagi ng pangunahing Xcode project. Ayon sa Swift.org Developer Survey (2024), 67% ng mga iOS developer ang gumagamit ng SPM, na ginagawa itong pinakasikat na tool sa pamamahala ng dependency sa Swift ecosystem.
Sinusuportahan ng SPM ang tatlong platform: Apple (iOS, macOS, tvOS, watchOS, visionOS), Linux (Ubuntu, CentOS, Amazon Linux), at server Swift (Vapor, Kitura). Sa Linux, ganap na gumagana ang SPM sa pamamagitan ng command line nang walang Xcode.
Ang SPM ay binuo sa paligid ng tatlong pangunahing konsepto: mga package (packages), mga produkto (products), at mga target (targets). Ang package ay isang Git repository na may manifest na Package.swift. Ang produkto ay resulta ng build (library o executable file). Ang target ay isang module sa loob ng package na nagko-compile sa isang build unit.
Kapag nagdagdag ang developer ng dependency sa Package.swift, ginagawa ng SPM ang mga sumusunod na hakbang:
~Library/Caches/org.swift.swiftpm/.Ang file na Package.resolved ay nagtatakda ng eksaktong bersyon ng lahat ng dependency upang ang team ng developer ay magtrabaho sa parehong set ng mga library. Ang file na ito ay dapat idagdag sa version control system (git).
Ang pangunahing bentahe ng SPM kumpara sa mga alternatibo — kawalan ng sentralisadong rehistro. Ang mga package ay maaaring nasa anumang pampublikong Git repository: GitHub, GitLab, Bitbucket, pati na rin sa sariling Git server ng kumpanya. Mula sa Swift 5.2, sinusuportahan ng SPM ang binary dependency (binary targets) — mga saradong library na ipinamamahagi sa pamamagitan ng XCFramework nang hindi nagbibigay ng source code.
Package.swift — ay isang Swift file na naglalarawan ng istraktura ng package at mga dependency nito. Ang file ay isinulat sa Swift mismo (hindi JSON, hindi YAML), na nagbibigay-daan sa paggamit ng conditional logic, computed constants, at functions sa loob ng manifest.
Pangunahing istraktura ng 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"]
),
]
)
Talakayin natin ang mga pangunahing elemento:
// swift-tools-version: 5.9 — directive na nagpapahiwatig ng bersyon ng SPM; ang magagamit na syntax ng manifest ay nakadepende dito.name — pangalan ng package na ipinapakita sa Xcode at ginagamit sa mga reference ng dependency.platforms — pinakamababang bersyon ng mga platform; hindi papayagan ng SPM na i-build ang package sa mas lumang bersyon ng OS.products — kung ano ang "ini-export" ng package: library (.library) o executable file (.executable).dependencies — listahan ng mga panlabas na package na may URL at bersyon; sinusuportahan ang from:, exact:, branch:, revision:.targets — mga build target; bawat target ay naglalaman ng listahan ng mga dependency, resources, at swift file mula sa kaukulang direktoryo (Sources/TargetName/).Halimbawa ng pagtukoy ng eksaktong bersyon, branch, at 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"),
]
Mula sa Swift 5.9, idinagdag ang suporta para sa static/framework at linkerSettings sa Package.swift, na nagbibigay-daan sa mas tumpak na configuration ng pag-link para sa static at dynamic na library.
Ang Swift Package Manager ay nagbibigay ng set ng mga command para sa pagtatrabaho sa pamamagitan ng terminal. Ang mga command ay pinapatakbo mula sa root directory ng package (kung saan matatagpuan ang Package.swift).
# Gumawa ng bagong package na may library
swift package init --type library
# Gumawa ng executable package (console application)
swift package init --type executable
# I-build ang proyekto
swift build
# I-build sa release configuration
swift build -c release
# Patakbuhin ang mga test
swift test
# Patakbuhin ang partikular na test
swift test --filter "MyLibraryTests/testExample"
# I-download at i-resolve ang mga dependency
swift package resolve
# I-update ang mga dependency sa pinakabagong available na bersyon
swift package update
# Ipakita ang dependency graph
swift package show-dependencies
# Linisin ang build cache
swift package clean
# Bumuo ng Xcode project (bago ang Xcode 11)
swift package generate-xcodeproj
Kapag nagtatrabaho sa loob ng Xcode, karamihan sa mga command na ito ay awtomatikong naisasagawa: ang mga dependency ay na-resolve kapag binuksan ang proyekto, ang build ay pinapatakbo gamit ang ⌘B, mga test gamit ang ⌘U. Gayunpaman, ang kaalaman sa mga terminal command ay kinakailangan para sa CI/CD pipelines (GitHub Actions, GitLab CI, Jenkins), kung saan hindi available ang Xcode.
Ang command na swift package resolve ay gumagawa o nag-a-update ng file na Package.resolved. Ang file na ito ay nagtatakda ng eksaktong bersyon ng lahat ng dependency, kabilang ang mga transitibo, at dapat idagdag sa git. Inirerekomenda na patakbuhin ang swift package update bago ang bawat bagong feature branch, upang magtrabaho sa kasalukuyang bersyon ng mga library.
Ang paggawa ng sariling SPM package ay kapaki-pakinabang para sa encapsulation ng business logic sa multi-module na proyekto at para sa pag-publish ng open-source library. Tingnan natin ang proseso nang hakbang-hakbang.
mkdir MyNetworkKit
cd MyNetworkKit
swift package init --type library
Ang command na swift package init ay gumagawa ng sumusunod na istraktura:
MyNetworkKit/
├── Package.swift
├── README.md
├── Sources/
│ └── MyNetworkKit/
│ └── MyNetworkKit.swift
└── Tests/
└── MyNetworkKitTests/
└── MyNetworkKitTests.swift
Awtomatikong nag-scan ang SPM ng mga direktoryo ng Sources/ at Tests/: bawat subdirectory sa loob ng Sources ay tumutugma sa isang target.
Magdagdag tayo ng mga dependency at i-configure ang mga target na platform:
// 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
}
}
I-push ang package sa Git repository at gumawa ng 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
Pagkatapos nito, kahit sinong developer ay maaaring kumonekta sa iyong package sa pamamagitan ng .package(url: "https://github.com/username/MyNetworkKit.git", from: "1.0.0").
Alamofire — ang pinakasikat na HTTP client para sa Swift. Idagdag natin ito sa pamamagitan ng SPM at magsagawa ng GET request.
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("Natanggap ang \(users.count) na user")
case .failure(let error):
print("Error: \(error.localizedDescription)")
}
}
}
Ang Swinject library ay nagbibigay ng DI container para sa Swift. Kumokonekta sa pamamagitan ng .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()
Ang swift-log package mula sa Apple — isang unified logging API na sumusuporta sa maraming backend (OSLog, console, file).
import Logging
var logger = Logger(label: "com.myapp.network")
logger.logLevel = .debug
logger.info("Nagsimula ang network request", metadata: [
"url": "\(requestURL)",
"method": "GET"
])
logger.warning("Lumampas sa 2 segundo ang oras ng pagtugon")
logger.error("Error sa koneksyon: walang internet")
Ang tatlong halimbawang ito ay sumasaklaw sa karaniwang mga sitwasyon ng paggamit ng SPM: HTTP clients, DI containers, at system infrastructure. Ang pagpili ng mga library ay hindi sinasadya — ang Alamofire, Swinject, at swift-log ay nasa top 20 pinakasikat na Swift package sa GitHub.
Kung ang proyekto ay gumagamit ng CocoaPods o Carthage, ang migration sa SPM ay ginagawa sa ilang hakbang. Ang proseso ay ligtas: ang mga SPM dependency ay maaaring magkasama sa CocoaPods at Carthage sa iisang proyekto, na nagpapahintulot ng gradual na migration.
.xcworkspace, buksan ang .xcodeproj, at gawin ang Clean Build Folder.rm -rf Carthage/ sa terminal.Noong 2025, sinusuportahan ng SPM ang karamihan ng mga sikat na Swift library. Ang mga exception ay ilang ObjC framework na walang module map (modulemap). Kung ang isang library ay hindi pa sumusuporta sa SPM — suriin ang seksyon ng Installation sa README nito; karamihan sa mga may-akda ay nagdagdag na ng SPM support sa mga pinakabagong bersyon.
Mga madalas itanong
Ang SPM ay naka-embed sa Swift compiler at Xcode, hindi nangangailangan ng pag-install sa pamamagitan ng gem o Homebrew. Ang CocoaPods ay gumagamit ng sentralisadong Specs registry at gumagawa ng hiwalay na workspace. Ang Carthage ay gumagana sa pamamagitan ng framework nang walang integration sa proyekto. Ang SPM ay ang tanging manager na isinama sa antas ng compiler: ang mga dependency ay nire-resolve, ni-ca-cache, at bina-build nang magkatulad sa pangunahing code.
Oo, sinusuportahan ng SPM ang mixed Swift + Objective-C projects. Ang mga ObjC file sa loob ng SPM package ay awtomatikong napupunta sa Umbrella Header sa kondisyon ng tamang modulemap. Gayunpaman, hindi sinusuportahan ng SPM ang static na ObjC library na walang module map. Inirerekomenda na kumonekta sa ObjC library sa pamamagitan ng SPM lamang kung nagbibigay sila ng modulemap o nakasulat sa purong C.
Gumagamit ang SPM ng semantic versioning (SemVer). Kung ang package A ay nangangailangan ng Alamofire 5.8+, at ang package B ay nangangailangan ng Alamofire 5.9+, pipili ang SPM ng bersyon 5.9.x na nakakatugon sa pareho. Kung ang conflict ay hindi naresolba (isang package ay nangangailangan ng 5.x, ang isa ay 6.x), mag-uulat ang SPM ng error. Sa ganoong kaso, kailangan mong i-update ang isa sa mga package o baguhin ang dependency sa isang bersyon na katugma sa parehong pangangailangan.
Sa macOS: ~Library/Caches/org.swift.swiftpm/ at ~/Library/Developer/Xcode/DerivedData/. Sa Linux: ~cache/swiftpm/. Sa pag-build, nag-ca-cache ang SPM ng source code at mga naka-compile na object file. Para ganap na linisin ang cache, patakbuhin ang swift package reset — ang command na ito ay nagtatanggal ng dependency cache at DerivedData para sa kasalukuyang proyekto.
Oo, simula sa Swift 5.2, sinusuportahan ng SPM ang binary targets. Ang saradong library ay ibinibigay bilang XCFramework, at sa Package.swift ay tinutukoy ang path sa .xcframework. Ang source code ay hindi isinasapubliko. Ang binary target ay tinutukoy sa pamamagitan ng .binaryTarget(name: "PrivateSDK", path: "Sources/PrivateSDK.xcframework"). Ito ay nagpapahintulot sa pagkonekta ng commercial SDK nang hindi lumalabag sa mga kasunduan sa lisensya.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din