Swiftが3系から4系に上がる現時点での各種パッケージマネージャを比較

Swiftが3系から4系に上がる現時点での各種パッケージマネージャを比較

iOS11が発表されXcode 9 betaをダウンロードでき、公式でSwift4.0が目前の中ついこの間にSwift.orgからマイグレーションガイドの項目が追加されていました。

Swift.org - Migrating to Swift 4

ここによるとSwift3.2、またはSwift4.0でのライブラリ配布でない場合はソースコードから直接依存させた方が良いとあります。

というのもSwift3.2からSwift4.0は互換性はあるのですが、Swift3.1以前は互換性が無いとのこと。

またSwift周りの環境が変わってきそうな中でライブラリ管理で使えるパッケージマネージャの予習・復習がてらに比較してみました。

iOS / macOSから始まりOSSになったSwiftですが、パッケージマネージャとして有名なのは以下3種類になります。

  • CocoaPods
  • Carthage
  • Swift Package Manager

それぞれ用途ごとに3つを比較しながら詳解していきます。

前提

  • Swift 4.0
    • Apple Swift version 4.0 (swiftlang-900.0.43 clang-900.0.22.8)
  • Xcode 9 beta 2
  • coocapods 1.3.0.beta.2
  • carthage 0.23.0

ソースコードの公開先

Swiftの各種パッケージマネージャは全てOSSとして公開されていて、GitHubからソースコードを確認することができます。

CocoaPods

github.com

Rubyで実装されていて、そのためかCocoaPods自体もRubyGemsの文化がそのまま引き継がれた形式になっています。

CocoaPods専用の巨大なリポジトリが存在しており、そこから指定のライブラリを取得してくる流れになっています。

Carthage

github.com

Swiftで実装されており、CocoaPodsが中央集権型のパッケージマネージャならCarthageは対照的でよりシンプルにライブラリを提供するためにGit経由でライブラリを導入します。

Swift Package Manager

github.com

Swift自体に内包されている言語として公式のパッケージマネージャになり、仕組み的にはCarthageに近くGit経由でライブラリを導入します。

他のパッケージマネージャとして違う点はiOS / macOSなどのAppleのプラットフォームには対応しておらずLinuxのみに対応しているのが大きな違いになります。

導入

CocoaPods

RubyGems

$ gem install cocoapods

gemからインストールします、gemの依存性を気にして間にbundlerを入れて管理するパターンも多いです。

(bundlerについては割愛)

Carthage

HomeBrew

$ brew install carthage

HomeBrewからインストールできます、他の方法だと.pkgを公開しているのでこちらからもインストールできます。

Swift Package Manager

Swift Package ManagerはSwift公式のパッケージマネージャとして言語自体に内包されているため特に導入の手順なくとも、Swiftの環境があれば使うことができます。

提供側のパッケージファイル

CocoaPods

{ライブラリ名}.podspec

https://guides.cocoapods.org/syntax/podspec.html

Pod::Spec.new do |spec|
  spec.name         = '{ライブラリ名}'
  spec.version      = '{Semantic Versioningなgit tag}'
  spec.license      = { :type => '{ライセンス形式}' }
  spec.homepage     = '{ライブラリのホームページURL}'
  spec.authors      = { '{作成名}' => '作成者のメールアドレス' }
  spec.summary      = '{ライブラリの概要}'
  spec.source       = { :git => '{ソースコードのURL}', :tag => '#{spec.version}' }
  spec.source_files = '{ライブラリのディレクトリ内でソースコードのパスを指定}' # Sourcesの下にあるコードを指定する場合はこうなる 'Sources/**/*.{swift,h,m}'
  spec.dependency = '{依存するライブラリ名}' # 複数ある場合は続けて 'spec.dependency = ...' と複数行に分けて書く
  spec.ios.deployment_target = "{対応してる中で最低なiOS version}"
  spec.osx.deployment_target = "{対応してる中で最低なmacOS version}"
  if spec.respond_to?(:watchos)
    spec.watchos.deployment_target = "{対応してる中で最低なwatchOS version}"
  end
  if spec.respond_to?(:tvos)
    spec.tvos.deployment_target = "{対応してる中で最低なtvOS version}"
  end
end

あとはここに記載したライブラリ名でCocoaPods側に登録をすることで

pod '{ライブラリ名}'

でCocoaPodsからライブラリを利用することができるようになります。

CocoaPods側に登録しない場合は直接GitのURLを指定することでライブラリを入れることができます。

Carthage

Swiftのdynamic libraryの仕組みを利用した配布方法を取るため提供側のパッケージファイルはありません。

なので配布する条件としては、

  • ライブラリのリポジトリのrootに{ライブラリ名}.xcprojectを用意する
  • dynamic framework用のスキームを用意する
  • Semantic Versioningのフォーマットに沿ったgit tagを打っておく

上記を満たしていることでライブラリ利用側からCarthageを経由してライブラリを導入することができます。

Swift Package Manager

Swift Package Managerはライブラリの提供側も利用側も同じフォーマットで扱うことができます。

提供側のリポジトリのルートにPackage.swiftがあれば利用側はライブラリをSwift Package Manager経由で利用することが可能になります。

利用側のパッケージファイル

どのパッケージマネージャもパッケージング用のファイルと、その依存を固定するためのロックファイルがペアで存在しています。

それぞれ表でまとめたものがこち

パッケージマネージャ CocoaPods Carthage Swift Package Manager
パッケージファイル Podfile Cartfile Package.swift
ロックファイル Podfile.lock Cartfile.resolved Package.pins

それでは実際にライブラリを導入する際にどう記載していくのかを試します。

ここでは一般的によく使われる通信用のライブラリであるAlamofireのSwift4対応branch導入を例にしていきます。

CocoaPods

guides.cocoapods.org

Podfile

target 'SampleProject' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for SampleProject
  pod 'Alamofire/Alamofire', :git => 'https://github.com/Alamofire/Alamofire', :branch => 'swift4'

  target 'SampleProjectTests' do
    inherit! :search_paths
    # Pods for testing
  end
end

Carthage

https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile

Cartfile

github 'Alamofire/Alamofire' 'swift4'

Swift Package Manager

Package.swift

// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.


import PackageDescription

let package = Package(
    name: "SamplePackage",
    products: [
        // Products define the executables and libraries produced by a package, and make them visible to other packages.
        .library(
            name: "SamplePackage",
            targets: ["SamplePackage"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        .package(url: "https://github.com/Alamofire/Alamofire.git", .branch("swift4"))
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
        .target(
            name: "SamplePackage",
            dependencies: ["Alamofire"]),
        .testTarget(
            name: "SamplePackageTests",
            dependencies: ["SamplePackage"]),
    ]
)

Swift4.0からSwift Package Managerのフォーマットが変わりました、従来のPackage.swiftと違う部分として新たにtargetsproductsが増えています。

上記はswift package initのコマンドで生成したPackage.swiftを編集しています。

もし古いPackage.swiftも使いつつSwift4.0のPackage.swiftにも対応する場合は古いPackage.swiftには swift-tools-version の記述を行わず新しいPackage.swiftの名前を

Package@swift-4.swiftの名前にすることでSwift3.2以前のSwiftでもそのパッケージを利用することが可能になります。

コマンド比較

一般的に使うであろうコメントでそれぞれ比較して見ました。

こうしてみるとCocoaPodsは1つのbranchで管理してるのもあり割とコマンドが充実してます。

操作 CocoaPods Carthage Swift Package Manager
基本コマンド pod carthage swift package
インストー pod install carthage bootstrap swift package resolve
アップデート確認 pod outdated carthage outdated -
アップデート pod update carthage update swift package update
パッケージの表示 - - swift package show-dependencies
パッケージの検索 pod search - -
利用可能なパッケージの表示 pod list - -
リセット pod deintegrate - swift package reset

終わりに

段々とSwiftの環境が充実していくことが実感できますね、最近は3種のパッケージマネージャに対応してるライブラリもよく見ます。

Swift Package ManagerがAppleのプラットフォームに対応すればまた情勢が変わりそうですが、それぞれのプロジェクト用途に合わせて選択できたら良いですね。