SPM(Swift Package Manager)は、サードパーティライブラリの接続、ビルド、更新を自動化するためにAppleが開発した、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年9月)でコマンドラインツールとして初めて登場し、Xcode 11(2019年)以降はグラフィカルインターフェースと完全に統合され、File → Add Packagesメニューから依存関係を追加できるようになりました。
SPMはGitリポジトリから依存関係のソースコードを自動的にダウンロードし、メインプロジェクトと並行してビルドし、結果をキャッシュして後続のビルドを高速化します。CocoaPodsとは異なり、SPMは別個のワークスペース(xcworkspace)を生成せず、依存関係はメインのXcodeプロジェクトの一部になります。Swift.org Developer Survey(2024)によると、67%のiOS開発者がSPMを使用しており、Swiftエコシステムで最も人気のある依存関係管理ツールとなっています。
SPMは3つのプラットフォームをサポートしています:Apple(iOS、macOS、tvOS、watchOS、visionOS)、Linux(Ubuntu、CentOS、Amazon Linux)、サーバーサイドSwift(Vapor、Kitura)。Linuxでは、SPMはXcodeなしで完全にコマンドラインで動作します。
SPMは3つの主要な概念に基づいて構築されています:パッケージ(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でテストが開始されます。ただし、Xcodeが利用できないCI/CDパイプライン(GitHub Actions、GitLab CI、Jenkins)ではターミナルコマンドの知識が必要です。
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パッケージは、複数のバックエンド(OSLog、コンソール、ファイル)をサポートする統一ロギングAPIを提供します。
import Logging
var logger = Logger(label: "com.myapp.network")
logger.logLevel = .debug
logger.info("ネットワークリクエストを開始しました", metadata: [
"url": "(requestURL)",
"method": "GET"
])
logger.warning("応答時間が2秒を超えました")
logger.error("接続エラー:インターネットなし")
これら3つの例は、SPMの典型的な使用シナリオ(HTTPクライアント、DIコンテナ、システムインフラストラクチャ)をカバーしています。ライブラリの選択は偶然ではありません。Alamofire、Swinject、swift-logはGitHubで最もスターの多いSwiftパッケージトップ20に含まれています。
プロジェクトが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ライブラリは、modulemapを提供するか純粋なCで書かれている場合にのみSPM経由で接続することをお勧めします。
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アプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。