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)، يستخدم 67% من مطوري iOS أداة SPM، مما يجعلها الأداة الأكثر شعبية لإدارة التبعيات في نظام 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/).

مثال على تحديد إصدار دقيق وفرع و commit:

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

# بناء في تهيئة الإصدار
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 الخاصة بك مفيد لتغليف منطق الأعمال في مشاريع متعددة الوحدات ولنشر المكتبات مفتوحة المصدر. دعنا نستعرض العملية خطوة بخطوة.

الخطوة 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 توفر واجهة برمجة تسجيل موحدة تدعم عدة خلفيات (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 من بين أفضل 20 حزمة Swift من حيث النجوم على GitHub.

الترحيل من CocoaPods و Carthage

إذا كان مشروعك يستخدم CocoaPods أو Carthage، فإن الترحيل إلى SPM يتم في بضع خطوات. العملية آمنة: يمكن لتبعيات SPM أن تتعايش مع CocoaPods و Carthage في نفس المشروع، مما يسمح بالترحيل التدريجي.

CocoaPods → SPM

  1. في Xcode: File ← Add Package Dependency، أدخل عنوان URL للحزمة.
  2. اختر الإصدار وأضف الحزمة إلى الأهداف المطلوبة.
  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 بدون خرائط وحدات. إذا كانت المكتبة لا تدعم SPM بعد — تحقق من قسم Installation في ملف README الخاص بها؛ معظم المؤلفين أضافوا بالفعل دعم SPM في الإصدارات الأخيرة.

الأسئلة الشائعة

كيف يختلف SPM عن CocoaPods و Carthage؟

SPM مدمج في مترجم Swift و Xcode، ولا يتطلب تثبيتًا عبر gem أو Homebrew. يستخدم CocoaPods سجلاً مركزيًا Specs وينشئ مساحة عمل منفصلة. يعمل Carthage عبر أطر بدون تكامل مع المشروع. 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، ويُحدد المسار إلى .xcframework في Package.swift. لا يتم كشف الكود المصدري. يُحدد الهدف الثنائي عبر .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. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا