SPM: چیست، Swift Package Manager و Package.swift

نویسنده: IT Sectr منتشر شده: 2026-02-13 زمان مطالعه: 11 دقیقه

SPM (Swift Package Manager) — مدیر بسته داخلی اکوسیستم Swift است که توسط Apple برای خودکارسازی اتصال، ساخت و به‌روزرسانی کتابخانه‌های شخص ثالث توسعه یافته است. SPM از نسخه 3.0 (سال 2016) بخشی از کامپایلر Swift است و نیاز به نصب جداگانه ندارد. برخلاف CocoaPods و Carthage، SPM مستقیماً با کامپایلر و Xcode ادغام شده است که آن را به ابزار استاندارد مدیریت وابستگی‌ها در پروژه‌های مدرن Swift تبدیل می‌کند. در این مقاله ساختار Package.swift، دستورات SPM، نوشتن بسته‌های اختصاصی و مهاجرت از مدیران جایگزین را بررسی خواهیم کرد.

نکات اصلی

  • SPM (Swift Package Manager) — مدیر بسته داخلی کامپایلر Swift که نیاز به نصب جداگانه ندارد؛ روی iOS، macOS، Linux و پلتفرم‌های سروری کار می‌کند.
  • Package.swift — فایل مانیفست که نام بسته، پلتفرم‌ها، وابستگی‌ها و ماژول‌های هدف (targets) را در قالبی اعلانی توصیف می‌کند.
  • SPM وابستگی‌ها را بر اساس نسخه‌گذاری معنایی (SemVer) حل می‌کند، کد منبع را کش می‌کند و بسته‌ها را به صورت موازی برای سرعت بیشتر می‌سازد.
  • دستورات: swift package init (ایجاد بسته)، swift package update (به‌روزرسانی وابستگی‌ها)، swift build (ساخت)، swift test (اجرای تست‌ها).
  • مهاجرت از CocoaPods/Carthage به SPM از طریق Xcode: File → Add Package Dependency، پس از آن podfile و Cartfile حذف می‌شوند.

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)، 67% از توسعه‌دهندگان iOS از SPM استفاده می‌کنند که آن را به محبوب‌ترین ابزار مدیریت وابستگی‌ها در اکوسیستم Swift تبدیل می‌کند.

SPM از سه پلتفرم پشتیبانی می‌کند: Apple (iOS، macOS، tvOS، watchOS، visionOS)، Linux (Ubuntu، CentOS، Amazon Linux) و Swift سروری (Vapor، Kitura). در لینوکس، SPM کاملاً از طریق خط فرمان و بدون Xcode کار می‌کند.

Swift Package Manager چگونه کار می‌کند

SPM حول سه مفهوم کلیدی ساخته شده است: بسته‌ها (packages)، محصولات (products) و اهداف (targets). بسته یک مخزن Git با مانیفست Package.swift است. محصول نتیجه ساخت (کتابخانه یا فایل اجرایی) است. هدف یک ماژول درون بسته است که به یک واحد ساخت کامپایل می‌شود.

وقتی توسعه‌دهنده وابستگی‌ای را در Package.swift اضافه می‌کند، SPM مراحل زیر را انجام می‌دهد:

  1. کلون کردن — SPM مخزن Git وابستگی را از URL مشخص شده دانلود می‌کند.
  2. حل نسخه — تگ‌های SemVer (مثلاً 2.1.3) را تحلیل کرده و نسخه مناسب را در محدوده مشخص شده انتخاب می‌کند.
  3. حل ترانزیتیو — وابستگی‌های وابستگی‌ها را بررسی کرده و گرافی بدون تداخل نسخه می‌سازد.
  4. کش کردن — کد منبع دانلود شده را در ~Library/Caches/org.swift.swiftpm/ ذخیره می‌کند.
  5. کامپایل — تمام اهداف بسته را با پرچم‌های پروژه اصلی می‌سازد.

فایل Package.resolved نسخه‌های دقیق همه وابستگی‌ها را ثابت می‌کند تا تیم توسعه با مجموعه یکسانی از کتابخانه‌ها کار کند. این فایل باید به سیستم کنترل نسخه (git) اضافه شود.

مزیت کلیدی SPM نسبت به رقبا — عدم وجود رجیستری متمرکز است. بسته‌ها می‌توانند در هر مخزن Git عمومی قرار داشته باشند: GitHub، GitLab، Bitbucket، و همچنین در سرورهای Git اختصاصی شرکت. از نسخه Swift 5.2، SPM از وابستگی‌های باینری (binary targets) پشتیبانی می‌کند — کتابخانه‌های بسته که از طریق XCFramework بدون ارائه کد منبع توزیع می‌شوند.

Package.swift — مانیفست پروژه

Package.swift — یک فایل Swift است که ساختار بسته و وابستگی‌های آن را توصیف می‌کند. فایل به خود زبان Swift نوشته می‌شود (نه JSON، نه YAML)، که امکان استفاده از منطق شرطی، ثابت‌های محاسبه‌شده و توابع درون مانیفست را فراهم می‌کند.

ساختار پایه Package.swift:

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/) است.

مثال تعیین نسخه دقیق، شاخه و کامیت:

swift
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 اضافه شده است که امکان پیکربندی دقیق‌تر لینکینگ برای کتابخانه‌های استاتیک و دینامیک را فراهم می‌کند.

دستورات اصلی SPM

Swift Package Manager مجموعه‌ای از دستورات را برای کار از طریق ترمینال ارائه می‌دهد. دستورات از دایرکتوری ریشه بسته (جایی که Package.swift قرار دارد) اجرا می‌شوند.

bash
# ایجاد یک بسته جدید با کتابخانه
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 اضافه شود. توصیه می‌شود قبل از هر شاخه feature جدید، swift package update را اجرا کنید تا با آخرین نسخه‌های کتابخانه‌ها کار کنید.

ایجاد بسته اختصاصی

ایجاد بسته SPM اختصاصی برای کپسوله‌سازی منطق کسب‌وکار در پروژه‌های چندماژوله و انتشار کتابخانه‌های open-source مفید است. فرآیند گام‌به‌گام را بررسی می‌کنیم.

گام 1: مقداردهی اولیه

bash
mkdir MyNetworkKit
cd MyNetworkKit
swift package init --type library

گام 2: ساختار دایرکتوری

دستور swift package init ساختار زیر را ایجاد می‌کند:

text
MyNetworkKit/
├── Package.swift
├── README.md
├── Sources/
│   └── MyNetworkKit/
│       └── MyNetworkKit.swift
└── Tests/
    └── MyNetworkKitTests/
        └── MyNetworkKitTests.swift

SPM به طور خودکار دایرکتوری‌های Sources/ و Tests/ را اسکن می‌کند: هر زیردایرکتوری درون Sources با یک هدف (target) مطابقت دارد.

گام 3: ویرایش Package.swift

وابستگی‌ها را اضافه کرده و پلتفرم‌های هدف را پیکربندی می‌کنیم:

swift
// 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"]
        ),
    ]
)

گام 4: نوشتن کد

swift
// 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
    }
}

گام 5: انتشار

بسته را به مخزن Git ارسال کرده و یک تگ SemVer ایجاد کنید:

bash
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") متصل کند.

نمونه‌های استفاده از SPM

مثال 1: اتصال Alamofire برای درخواست‌های شبکه

Alamofire — محبوب‌ترین کلاینت HTTP برای Swift است. آن را از طریق SPM اضافه کرده و یک درخواست GET اجرا می‌کنیم.

swift
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)")
            }
        }
}

مثال 2: Swinject — تزریق وابستگی

کتابخانه Swinject یک کانتینر DI برای Swift ارائه می‌دهد. از طریق .package(url: "https://github.com/Swinject/Swinject.git", from: "2.8.0") متصل می‌شود.

swift
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()

مثال 3: Swift-log برای لاگ‌گیری ساختاریافته

بسته swift-log از Apple — یک API لاگ‌گیری یکپارچه که از بک‌اندهای متعدد (OSLog، کنسول، فایل‌ها) پشتیبانی می‌کند.

swift
import Logging

var logger = Logger(label: "com.myapp.network")
logger.logLevel = .debug

logger.info("درخواست شبکه آغاز شد", metadata: [
    "url": "\(requestURL)",
    "method": "GET"
])

logger.warning("زمان پاسخ از ۲ ثانیه فراتر رفت")
logger.error("خطای اتصال: اینترنت در دسترس نیست")

این سه مثال سناریوهای معمول استفاده از SPM را پوشش می‌دهند: کلاینت‌های HTTP، کانتینرهای DI و زیرساخت سیستمی. انتخاب کتابخانه‌ها تصادفی نیست — Alamofire، Swinject و swift-log در بین ۲۰ بسته محبوب Swift در GitHub قرار دارند.

مهاجرت از CocoaPods و Carthage

اگر پروژه از CocoaPods یا Carthage استفاده می‌کند، مهاجرت به SPM در چند مرحله انجام می‌شود. فرآیند امن است: وابستگی‌های SPM می‌توانند با CocoaPods و Carthage در یک پروژه共存 داشته باشند که امکان مهاجرت تدریجی را فراهم می‌کند.

CocoaPods → SPM

  1. در Xcode: File → Add Package Dependency، URL بسته را وارد کنید.
  2. نسخه را انتخاب کرده و بسته را به targets مورد نظر اضافه کنید.
  3. پس از افزودن همه وابستگی‌ها از طریق SPM، خطوط را از Podfile حذف کنید.
  4. .xcworkspace را حذف کرده، .xcodeproj را باز کرده و Clean Build Folder را اجرا کنید.

Carthage → SPM

  1. بسته‌ها را از طریق Xcode File → Add Package Dependency اضافه کنید.
  2. وابستگی‌ها را از Cartfile حذف کنید.
  3. اسکریپت‌های ساخت Carthage را از Build Phases حذف کنید.
  4. کش را پاک کنید: در ترمینال rm -rf Carthage/.

تا سال 2025، SPM از اکثریت قریب‌به‌اتفاق کتابخانه‌های محبوب Swift پشتیبانی می‌کند. استثناها برخی فریم‌ورک‌های ObjC بدون نقشه ماژول (modulemap) هستند. اگر کتابخانه‌ای هنوز از SPM پشتیبانی نمی‌کند — بخش Installation را در README آن بررسی کنید؛ بیشتر نویسندگان در آخرین نسخه‌ها پشتیبانی SPM را اضافه کرده‌اند.

سوالات متداول

تفاوت SPM با CocoaPods و Carthage چیست؟

SPM در کامپایلر Swift و Xcode تعبیه شده است و نیازی به نصب از طریق gem یا Homebrew ندارد. CocoaPods از رجیستری متمرکز Specs استفاده می‌کند و یک workspace جداگانه تولید می‌کند. Carthage از طریق فریم‌ورک‌ها بدون ادغام با پروژه کار می‌کند. SPM تنها مدیری است که در سطح کامپایلر ادغام شده است: وابستگی‌ها حل، کش و به موازات کد اصلی ساخته می‌شوند.

آیا می‌توان از SPM برای پروژه‌های Objective-C استفاده کرد؟

بله، SPM از پروژه‌های ترکیبی Swift + Objective-C پشتیبانی می‌کند. فایل‌های ObjC درون بسته SPM به شرط وجود modulemap صحیح به صورت خودکار در Umbrella Header قرار می‌گیرند. با این حال، SPM از کتابخانه‌های استاتیک ObjC که نقشه ماژول ندارند پشتیبانی نمی‌کند. توصیه می‌شود کتابخانه‌های ObjC را از طریق SPM فقط در صورتی متصل کنید که modulemap ارائه می‌دهند یا به زبان خالص C نوشته شده‌اند.

SPM چگونه تداخلات نسخه را حل می‌کند؟

SPM از نسخه‌گذاری معنایی (SemVer) استفاده می‌کند. اگر بسته A به Alamofire 5.8+ و بسته B به Alamofire 5.9+ نیاز داشته باشد، SPM نسخه 5.9.x را که هر دو نیاز را برآورده می‌کند انتخاب می‌کند. اگر تداخل غیرقابل حل باشد (یک بسته به 5.x و دیگری به 6.x نیاز دارد)، SPM خطا گزارش می‌دهد. در این صورت باید یکی از بسته‌ها را به‌روزرسانی کنید یا وابستگی را به نسخه‌ای تغییر دهید که با هر دو نیاز سازگار باشد.

بسته‌های SPM دانلود شده کجا ذخیره می‌شوند؟

در macOS: ~Library/Caches/org.swift.swiftpm/ و ~/Library/Developer/Xcode/DerivedData/. در Linux: ~cache/swiftpm/. هنگام ساخت، SPM کد منبع و فایل‌های آبجکت کامپایل شده را کش می‌کند. برای پاک کردن کامل کش، swift package reset را اجرا کنید — این دستور کش وابستگی‌ها و DerivedData را برای پروژه جاری حذف می‌کند.

آیا SPM از کتابخانه‌های بسته (انحصاری) پشتیبانی می‌کند؟

بله، از Swift 5.2، SPM از اهداف باینری (binary targets) پشتیبانی می‌کند. کتابخانه بسته به عنوان XCFramework ارائه می‌شود و در Package.swift مسیر .xcframework مشخص می‌شود. کد منبع فاش نمی‌شود. Binary target از طریق .binaryTarget(name: "PrivateSDK", path: "Sources/PrivateSDK.xcframework") مشخص می‌شود. این امکان اتصال SDKهای تجاری را بدون نقض توافق‌نامه‌های مجوز فراهم می‌کند.

جمع‌بندی

  • SPM (Swift Package Manager) — مدیر بسته داخلی Swift که نیاز به نصب جداگانه ندارد و با Xcode و کامپایلر ادغام شده است.
  • Package.swift — مانیفست اعلانی به زبان Swift که نام بسته، پلتفرم‌ها، وابستگی‌ها، محصولات و اهداف ساخت را توصیف می‌کند.
  • SPM از مخازن Git به عنوان منبع بسته‌ها استفاده می‌کند و نسخه‌ها را بر اساس SemVer حل می‌کند، کد منبع را برای سرعت بخشیدن به ساخت‌های بعدی کش می‌کند.
  • دستورات اصلی: swift package init (ایجاد بسته)، swift build (ساخت)، swift test (تست)، swift package update (به‌روزرسانی وابستگی‌ها).
  • بسته اختصاصی از طریق swift package init ایجاد می‌شود، در Git منتشر می‌شود و از طریق URL با تگ SemVer برای پروژه‌های دیگر در دسترس است.
  • مهاجرت از CocoaPods/Carthage به SPM امن است: وابستگی‌ها می‌توانند共存 داشته باشند، مهاجرت از طریق File → Add Package Dependency در Xcode انجام می‌شود.
  • SPM — استاندارد مدیریت وابستگی‌ها در اکوسیستم Swift است که توسط 67% از توسعه‌دهندگان iOS استفاده می‌شود (Swift.org Developer Survey, 2024).

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید