SPM (Swift Package Manager) হল Swift ইকোসিস্টেমের একটি অন্তর্নির্মিত প্যাকেজ ব্যবস্থাপক, যা অ্যাপল তৃতীয়-পক্ষের লাইব্রেরি সংযুক্ত, বিল্ড এবং আপডেট করার স্বয়ংক্রিয়তার জন্য তৈরি করেছে। SPM সংস্করণ 3.0 (2016) থেকে Swift কম্পাইলারের অংশ এবং আলাদা ইনস্টলেশনের প্রয়োজন নেই। 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) অনুসারে, 67% iOS ডেভেলপার SPM ব্যবহার করে, যা এটিকে Swift ইকোসিস্টেমে সবচেয়ে জনপ্রিয় নির্ভরতা ব্যবস্থাপনা টুল করে তুলেছে।
SPM তিনটি প্ল্যাটফর্ম সমর্থন করে: Apple (iOS, macOS, tvOS, watchOS, visionOS), Linux (Ubuntu, CentOS, Amazon Linux) এবং সার্ভার-সাইড Swift (Vapor, Kitura)। Linux-এ, SPM Xcode ছাড়া সম্পূর্ণরূপে কমান্ড লাইনের মাধ্যমে কাজ করে।
SPM তিনটি মূল ধারণার চারপাশে নির্মিত: প্যাকেজ (packages), পণ্য (products) এবং লক্ষ্য (targets)। প্যাকেজ হল Package.swift ম্যানিফেস্ট সহ একটি Git রিপোজিটরি। পণ্য হল বিল্ডের ফলাফল (একটি লাইব্রেরি বা নির্বাহযোগ্য ফাইল)। লক্ষ্য হল প্যাকেজের ভিতরের একটি মডিউল যা একটি বিল্ড ইউনিটে কম্পাইল হয়।
যখন একজন ডেভেলপার Package.swift-এ একটি নির্ভরতা যোগ করে, SPM নিম্নলিখিত ধাপগুলি সম্পাদন করে:
~Library/Caches/org.swift.swiftpm/-এ সংরক্ষণ করে।Package.resolved ফাইল সমস্ত নির্ভরতার সঠিক সংস্করণ লক করে যাতে ডেভেলপমেন্ট টিম লাইব্রেরির অভিন্ন সেট নিয়ে কাজ করে। এই ফাইলটি সংস্করণ নিয়ন্ত্রণে (git) যুক্ত করা উচিত।
বিকল্পগুলির তুলনায় SPM-এর একটি মূল সুবিধা হল কেন্দ্রীভূত রেজিস্ট্রির অনুপস্থিতি। প্যাকেজ যেকোনো পাবলিক Git রিপোজিটরিতে থাকতে পারে: GitHub, GitLab, Bitbucket, পাশাপাশি কোম্পানির ব্যক্তিগত Git সার্ভারেও। Swift 5.2 থেকে, SPM বাইনারি নির্ভরতা (বাইনারি টার্গেট) সমর্থন করে — সোর্স কোড না দিয়ে XCFramework হিসাবে বিতরণ করা ক্লোজ-সোর্স লাইব্রেরি।
Package.swift হল একটি Swift ফাইল যা প্যাকেজের গঠন এবং এর নির্ভরতা বর্ণনা করে। ফাইলটি Swift ভাষায় লেখা (JSON বা YAML নয়), যা ম্যানিফেস্টের ভিতরে শর্তসাপেক্ষ যুক্তি, গণনাকৃত ধ্রুবক এবং ফাংশন ব্যবহারের সুযোগ দেয়।
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 সংস্করণ নির্দিষ্ট করে; এর উপর ম্যানিফেস্টের উপলব্ধ সিনট্যাক্স নির্ভর করে।name — প্যাকেজের নাম, Xcode-এ প্রদর্শিত হয় এবং নির্ভরতা লিংকে ব্যবহৃত হয়।platforms — ন্যূনতম প্ল্যাটফর্ম সংস্করণ; SPM পুরনো OS সংস্করণে প্যাকেজ বিল্ড করার অনুমতি দেবে না।products — প্যাকেজ কী "রপ্তানি" করে: একটি লাইব্রেরি (.library) বা একটি নির্বাহযোগ্য (.executable)।dependencies — URL এবং সংস্করণ সহ বাহ্যিক প্যাকেজের তালিকা; from:, exact:, branch:, revision: সমর্থন করে।targets — বিল্ড লক্ষ্য; প্রতিটি লক্ষ্যে সংশ্লিষ্ট ডিরেক্টরি (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-এর জন্য সমর্থন যুক্ত করেছে, যা স্ট্যাটিক এবং ডায়নামিক লাইব্রেরির জন্য আরও সঠিক লিংকার কনফিগারেশন অনুমোদন করে।
Swift Package Manager টার্মিনালের মাধ্যমে কাজ করার জন্য কমান্ডের একটি সেট প্রদান করে। কমান্ড প্যাকেজের মূল ডিরেক্টরি (যেখানে Package.swift অবস্থিত) থেকে চালানো হয়।
# লাইব্রেরি সহ নতুন প্যাকেজ তৈরি করুন
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 প্যাকেজ তৈরি করা মাল্টি-মডিউল প্রকল্পে ব্যবসায়িক যুক্তি এনক্যাপসুলেট করার এবং ওপেন-সোর্স লাইব্রেরি প্রকাশের জন্য উপযোগী। আসুন ধাপে ধাপে প্রক্রিয়াটি দেখি।
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-এর ভিতরের প্রতিটি উপডিরেক্টরি একটি লক্ষ্য (টার্গেট) এর সাথে মিলে যায়।
চলুন নির্ভরতা যোগ করি এবং লক্ষ্য প্ল্যাটফর্ম কনফিগার করি:
// 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 হল Swift-এর জন্য সবচেয়ে জনপ্রিয় HTTP ক্লায়েন্ট। আসুন এটি 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 লাইব্রেরি Swift-এর জন্য একটি DI কন্টেইনার প্রদান করে। এটি .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()
Apple-এর swift-log প্যাকেজ একটি একীভূত লগিং API প্রদান করে যা একাধিক ব্যাকএন্ড (OSLog, কনসোল, ফাইল) সমর্থন করে।
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 GitHub-এ সবচেয়ে বেশি স্টার প্রাপ্ত শীর্ষ ২০টি Swift প্যাকেজের মধ্যে রয়েছে।
যদি আপনার প্রকল্প CocoaPods বা Carthage ব্যবহার করে, SPM-এ মাইগ্রেশন কয়েকটি ধাপে করা হয়। প্রক্রিয়াটি নিরাপদ: SPM নির্ভরতা একই প্রকল্পে CocoaPods এবং Carthage-এর সাথে সহাবস্থান করতে পারে, যা ধীরে ধীরে মাইগ্রেশনের অনুমতি দেয়।
.xcworkspace মুছুন, .xcodeproj খুলুন এবং Clean Build Folder করুন।rm -rf Carthage/ চালান।2025 পর্যন্ত, SPM অধিকাংশ জনপ্রিয় Swift লাইব্রেরি সমর্থন করে। ব্যতিক্রম হল কিছু ObjC ফ্রেমওয়ার্ক যেখানে মডিউল ম্যাপ নেই। যদি কোনো লাইব্রেরি এখনও SPM সমর্থন না করে — তার README-তে Installation বিভাগ দেখুন; বেশিরভাগ লেখক ইতিমধ্যে সর্বশেষ সংস্করণে SPM সমর্থন যুক্ত করেছেন।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
SPM Swift কম্পাইলার এবং Xcode-এ নির্মিত, এটি gem বা Homebrew-এর মাধ্যমে ইনস্টলেশনের প্রয়োজন নেই। CocoaPods একটি কেন্দ্রীভূত Specs রেজিস্ট্রি ব্যবহার করে এবং আলাদা ওয়ার্কস্পেস তৈরি করে। Carthage প্রকল্প একীকরণ ছাড়া ফ্রেমওয়ার্কের মাধ্যমে কাজ করে। SPM একমাত্র ব্যবস্থাপক যা কম্পাইলার স্তরে একীভূত: নির্ভরতা মূল কোডের সাথে সমান্তরালভাবে সমাধান, ক্যাশ এবং বিল্ড করা হয়।
হ্যাঁ, SPM মিশ্র Swift + Objective-C প্রকল্প সমর্থন করে। SPM প্যাকেজের ভিতরে ObjC ফাইলগুলি সঠিক modulemap থাকলে স্বয়ংক্রিয়ভাবে Umbrella Header-এ অন্তর্ভুক্ত হয়। তবে, 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 বাইনারি টার্গেট সমর্থন করে। একটি ক্লোজ-সোর্স লাইব্রেরি XCFramework হিসাবে বিতরণ করা হয় এবং .xcframework-এর পথ Package.swift-এ নির্দিষ্ট করা হয়। সোর্স কোড উন্মুক্ত হয় না। বাইনারি টার্গেট .binaryTarget(name: "PrivateSDK", path: "Sources/PrivateSDK.xcframework")-এর মাধ্যমে নির্দিষ্ট করা হয়। এটি লাইসেন্স চুক্তি লঙ্ঘন না করে বাণিজ্যিক SDK সংযুক্ত করার অনুমতি দেয়।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন