Swiftパッケージマネージャー



2015年12月3日のオープンソースSwift言語でのリリースに伴い、Appleは分散型依存関係マネージャーSwift Package Managerを導入しました。



Homebrewの作成者である悪名高いMax HowellAFNetworkingを書いたMatt Thompsonは、公開版に手を携えていた。 SwiftPMは、依存関係のインストールプロセスを自動化するように設計されており、利用可能なすべてのオペレーティングシステムでSwiftでプロジェクトをさらにテストおよびビルドしますが、これまでサポートしているのはmacOSとLinuxのみです。 興味がある場合は、猫の下に行きます。



最小要件はSwift 3.0です。 プロジェクトファイルを開くには、Xcode 8.0以降が必要です。 SwiftPMでは、xcodeprojファイルなしでプロジェクトを操作できるため、OS XのXcodeはオプションですが、Linuxではそうではありません。



疑問を払拭する価値があります-プロジェクトはまだ活発に開発されています。 SwiftPMはソースコードの形式で依存関係を接続し、収集するため、UIKit、AppKit、およびその他のiOSおよびOS X SDKフレームワークを依存関係として使用することはできません。 したがって、iOSでSwiftPM、watchOS、およびtvOSを使用することは可能ですが、Foundationとサードパーティライブラリの依存関係を使用するのはオープンアクセスのみです。 単一のインポートUIKitにより、SwiftPMでライブラリを使用できなくなります。



この記事のすべての例は、バージョン4.0.0-devを使用して記述されています。ターミナルのコマンドを使用してバージョンを確認できます。



swift package —version
      
      





Ideology Swift Package Manager



プロジェクトで作業するために、* .xcodprojファイルは不要になりました-補助ツールとして使用できるようになりました。 モジュールのアセンブリに関係するファイルは、ディスク上の場所によって異なります。SwiftPMにとって、プロジェクト内のディレクトリ名と階層は重要です。 プロジェクトディレクトリの初期構造は次のとおりです。





SourcesおよびTestsフォルダー内で、SwiftPMはすべての* .swiftファイルを再帰的に検索し、それらをルートフォルダーに関連付けます。 少し後で、ファイルを含むサブフォルダーを作成します。







主なコンポーネント



次に、SwiftPMの主要コンポーネントを見てみましょう。









依存関係がグラフに配置されていることを取得します-各依存関係は独自のものを持つことができます。 依存関係グラフの解決は、依存関係マネージャーの主なタスクです。



すべてのソースファイルはSwiftで作成する必要があり、Objective-Cを使用する可能性はありません。



各パッケージは自己完結型で隔離されている必要があります。 そのデバッグは、開始(実行)ではなく、論理テスト(テスト)によって実行されます。



以下は、Alamofire依存関係をプロジェクトに接続する簡単な例です。



テストプロジェクト開発



ターミナルを介して、プロジェクトのあるフォルダーに移動し、そのディレクトリを作成して、そこに移動します。



 mkdir IPInfoExample cd IPInfoExample/
      
      





次に、コマンドを使用してパッケージを初期化します



 swift package init
      
      





その結果、次のソースファイルの階層が作成されます。



 ├── Package.swift ├── README.md ├── Sources │ └── IPInfoExample │ └── main.swift └── Tests └── IPInfoExampleTests ├ LinuxMain.swift └── IPInfoExampleTests └── IPInfoExampleTests.swift
      
      





* .xcodeprojプロジェクトファイルのインデックスがない場合、依存関係マネージャーは、ビルドプロセスに含める必要があるソースファイルと、それらを含めるターゲットを知る必要があります。 したがって、SwiftPMはフォルダーの厳密な階層とファイルのリストを定義します。





これでコマンドを実行できます



 swift build swift test
      
      





パッケージをビルドするか、テストを実行するにはHello、world!



ソースファイルを追加する



Application.swiftファイルを作成し、IPInfoExampleフォルダーに配置します。



 public struct Application {}
      
      







迅速なビルドを実行し、2つのファイルがモジュールで既にコンパイルされていることを確認します。



 Compile Swift Module 'IPInfoExample' (2 sources)
      
      





IPInfoExampleフォルダーにModelディレクトリを作成し、IPInfo.swiftファイルを作成し、不要な場合はIPInfoExample.swiftファイルを削除します。



 //  Codable   JSON   public struct IPInfo: Codable { let ip: String let city: String let region: String let country: String }
      
      





その後、swift buildコマンドを実行して確認します。



依存関係を追加



Package.swiftファイルを開いてみましょう。コンテンツはパッケージを完全に説明しています:パッケージ名、依存関係、ターゲット。 Alamofire依存関係を追加します。



 // swift-tools-version:4.0 import PackageDescription // ,      let package = Package( name: "IPInfoExample", //    products: [ .library( name: "IPInfoExample", targets: ["IPInfoExample"]), ], dependencies: [ //  - Alamofire,    GitHub .package(url: "https://github.com/Alamofire/Alamofire.git", from: "4.0.0") ], targets: [ .target( name: "IPInfoExample", //    – ,   //   Alamofire dependencies: ["Alamofire"]), .testTarget( name: "IPInfoExampleTests", dependencies: ["IPInfoExample"]), ] )
      
      





再度、迅速なビルドが行われ、依存関係がダウンロードされ、インストールされた依存関係の説明を含むPackage.resolvedファイルが作成されます(Podfile.lockと同様)。



パッケージに製品が1つしかない場合、パッケージ名、製品、およびターゲットに同じ名前を使用できます。 このIPInfoExampleがあります。 したがって、製品のパラメーターを省略することで、パッケージの説明を短縮できます。 Alamofireパッケージの説明を見ると、ターゲットがそこに記述されていないことがわかります。 デフォルトでは、Sourcesフォルダーのパッケージ名とソースコードファイルを使用して1つのターゲットが作成され、パッケージ記述ファイル(PackageDescription)を使用して1つのターゲットが作成されます。 SwiftPMを使用する場合、テストターゲットは関係しないため、テストフォルダーは除外されます。



 import PackageDescription let package = Package(name: "Alamofire", dependencies : [], exclude: [“Tests"])
      
      





モジュール、ターゲット、製品が正しく作成されたことを確認するために、コマンドを実行できます



 swift package describe
      
      





その結果、Alamofireの場合、次のログが取得されます。



 Name: Alamofire Path: /Users/ivanvavilov/Documents/Xcode/Alamofire Modules: Name: Alamofire C99name: Alamofire Type: library Module type: SwiftTarget Path: /Users/ivanvavilov/Documents/Xcode/Alamofire/Source Sources: AFError.swift, Alamofire.swift, DispatchQueue+Alamofire.swift, MultipartFormData.swift, NetworkReachabilityManager.swift, Notifications.swift, ParameterEncoding.swift, Request.swift, Response.swift, ResponseSerialization.swift, Result.swift, ServerTrustPolicy.swift, SessionDelegate.swift, SessionManager.swift, TaskDelegate.swift, Timeline.swift, Validation.swift
      
      





パッケージに複数の製品がある場合、依存関係として依存関係パッケージを指定し、既にターゲット依存関係にあるパッケージモジュールへの依存関係を示します。 たとえば、これはSourceKittenがSynopsisライブラリでどのように接続されるかです。



 import PackageDescription let package = Package( name: "Synopsis", products: [ Product.library( name: "Synopsis", targets: ["Synopsis"] ), ], dependencies: [ Package.Dependency.package( //    SourceKitten url: "https://github.com/jpsim/SourceKitten", from: "0.18.0" ), ], targets: [ Target.target( name: "Synopsis", //    SourceKittenFramework dependencies: ["SourceKittenFramework"] ), Target.testTarget( name: "SynopsisTests", dependencies: ["Synopsis"] ), ] )
      
      





これは、 SourceKittenパッケージの説明です。 パッケージには2つの製品が記載されています



 .executable(name: "sourcekitten", targets: ["sourcekitten"]), .library(name: "SourceKittenFramework", targets: ["SourceKittenFramework"])
      
      





概要では、SourceKittenFramework製品ライブラリを使用します。



プロジェクトファイルを作成する



次のコマンドを実行して、便利なプロジェクトファイルを作成できます。



 swift package generate-xcodeproj
      
      





その結果、プロジェクトのルートフォルダーにIPInfoExample.xcodeprojファイルを取得します。

それを開いて、Sourcesフォルダー内のすべてのソース(Modelサブフォルダーを持つソースを含む)、およびDependenciesフォルダー内の依存関係ソースを確認します。



このステップは製品開発中のオプションであり、SwiftPM操作メカニズムに影響を与えないことに注意することが重要です。 すべてのソースファイルはディスクと同じ方法で配置されることに注意してください。







接続された依存関係の確認



依存関係が正しく接続されているかどうかを確認してください。 この例では、現在のIPアドレスに関するデータを取得するために、ipinfoサービスに非同期要求を行います。 応答JSONをモデルオブジェクト(IPInfo構造)にデコードします。 簡単にするために、JSONマッピングエラーまたはサーバーエラーは処理しません。



 //    ,    cocoapods  carthage import Alamofire import Foundation public typealias IPInfoCompletion = (IPInfo?) -> Void public struct Application { public static func obtainIPInfo(completion: @escaping IPInfoCompletion) { Alamofire .request("https://ipinfo.io/json") .responseData { result in var info: IPInfo? if let data = result.data { //  JSON    info = try? JSONDecoder().decode(IPInfo.self, from: data) } completion(info) } } }
      
      





次に、Xcodeでbuildコマンドを使用し、ターミナルでswift buildコマンドを実行できます。



実行可能ファイルを含むプロジェクト



上記は、ライブラリプロジェクトを初期化する例です。 SwiftPMを使用すると、実行可能ファイルプロジェクトを操作できます。 これを行うには、初期化時に次のコマンドを使用します



 swift package init —type executable.
      
      





Sources / IPInfoExampleディレクトリにmain.swiftファイルを作成して、現在のプロジェクトをこのフォームに取り込むこともできます。 実行可能ファイルを実行すると、main.swiftがエントリポイントになります。

その中に1行書きましょう



 print("Hello, world!”)
      
      





そして、swift runコマンドを実行すると、大切な文がコンソールに表示されます。



パッケージ記述構文



一般的なパッケージの説明は次のとおりです。



 Package( name: String, pkgConfig: String? = nil, providers: [SystemPackageProvider]? = nil, products: [Product] = [], dependencies: [Dependency] = [], targets: [Target] = [], swiftLanguageVersions: [Int]? = nil )
      
      







 import PackageDescription let package = Package( name: "CGtk3", pkgConfig: "gtk+-3.0", providers: [ .brew(["gtk+3"]), .apt(["gtk3"]) ] )
      
      







 let package = Package( name: "Paper", products: [ .executable(name: "tool", targets: ["tool"]), .library(name: "Paper", targets: ["Paper"]), .library(name: "PaperStatic", type: .static, targets: ["Paper"]), .library(name: "PaperDynamic", type: .dynamic, targets: ["Paper"]) ], targets: [ .target(name: "tool") .target(name: "Paper") ] )
      
      





上記のパッケージには、ツールターゲットからの実行可能ファイル、Paperライブラリ(SwiftPMが自動的にタイプを選択する)、静的PaperStaticライブラリ、1つのPaperターゲットからの動的PaperDynamicの4つの製品があります。





 // 1.0.0 ..< 2.0.0 .package(url: "/SwiftyJSON", from: "1.0.0"), // 1.2.0 ..< 2.0.0 .package(url: "/SwiftyJSON", from: "1.2.0"), // 1.5.8 ..< 2.0.0 .package(url: "/SwiftyJSON", from: "1.5.8"), // 1.5.8 ..< 2.0.0 .package(url: "/SwiftyJSON", .upToNextMajor(from: "1.5.8")), // 1.5.8 ..< 1.6.0 .package(url: "/SwiftyJSON", .upToNextMinor(from: "1.5.8")), // 1.5.8 .package(url: "/SwiftyJSON", .exact("1.5.8")), //   . .package(url: "/SwiftyJSON", "1.2.3"..<"1.2.6"), //    . .package(url: "/SwiftyJSON", .branch("develop")), .package(url: "/SwiftyJSON", .revision("e74b07278b926c9ec6f9643455ea00d1ce04a021"))
      
      







 let package = Package( name: "FooBar", targets: [ .target(name: "Foo", dependencies: []), .testTarget(name: "Bar", dependencies: ["Foo"]) ] )
      
      







チームインデックス



 swift package init //   swift package init --type executable //    swift package --version //  SwiftPM swift package update //  swift package show-dependencies //   swift package describe //   
      
      





資源






All Articles