SPM: какво е това, Swift Package Manager и Package.swift

Автор: IT Sectr Публикувано: 2026-02-13 Време за четене: 11 мин

SPM (Swift Package Manager) — вграденият мениджър на пакети на екосистемата Swift, разработен от Apple за автоматизиране на свързването, изграждането и актуализирането на библиотеки на трети страни. SPM е част от компилатора на Swift от версия 3.0 (2016 г.) и не изисква отделна инсталация. За разлика от 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 не генерира отделно работно пространство (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.

Как работи 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 в Package.swift е добавена поддръжка за static/framework и linkerSettings, което позволява по-прецизна конфигурация на свързването за статични и динамични библиотеки.

Основни команди на 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. Препоръчва се стартиране на swift package update преди всеки нов feature клон, за да работите с актуални версии на библиотеките.

Създаване на собствен пакет

Създаването на собствен 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 за логване, поддържащ множество backend (OSLog, конзола, файлове).

swift
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

Ако проектът използва 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 frameworks без модулни карти (modulemap). Ако библиотека все още не поддържа SPM — проверете секцията Installation в нейния README; повечето автори вече са добавили поддръжка на SPM в най-новите версии.

Често задавани въпроси

По какво SPM се различава от CocoaPods и Carthage?

SPM е вграден в компилатора на Swift и Xcode, не изисква инсталация чрез gem или Homebrew. CocoaPods използва централизиран регистър Specs и генерира отделно работно пространство. Carthage работи чрез frameworks без интеграция с проекта. SPM е единственият мениджър, интегриран на ниво компилатор: зависимостите се разрешават, кешират и изграждат паралелно с основния код.

Може ли SPM да се използва за Objective-C проекти?

Да, SPM поддържа смесени Swift + Objective-C проекти. ObjC файловете в рамките на SPM пакет автоматично попадат в Umbrella Header при условие на коректен modulemap. Въпреки това, 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 създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също