Swift Package Manager(如下簡稱SPM)是蘋果在swift3.0中加入的一個包管理工具,用於處理模塊代碼的下載、編譯和依賴關係等。跟CocoaPods和Carthage功能相似,不過比這兩個更簡潔,代碼的侵入性更小,也不須要額外安裝工具。git
須要注意的是,SPM在swift4.0中從新設計了API,因此你須要肯定你當前使用的swift版本,不然極可能會出現build失敗的狀況,如下代碼都是基於swift4.0版本。github
既然是包管理,因此咱們的操做都是以包的形式,依賴的第三方庫都會當成一個個單獨的包來處理,依賴包能夠嵌套。macos
SPM包含兩種包:可執行的二進制包(executable)和靜態庫包(Library),二者惟一的區別就是前者會生成二進制可執行文件,能夠直接用命令行執行。若是建立的是Library,用命令行執行會提示沒有可執行文件,這個時候只須要在Sources/目錄下建立一個main.swift文件就能夠執行了。json
一、經過命令建立包:swift
$ mkdir SPMDemo
$ cd SPMDemo
$ swift package init --type executable(or library) //初始化包,不帶參數的話默認是Library
Creating executable package: SPMDemo
Creating Package.swift
Creating .gitignore
Creating Sources/
Creating Sources/main.swift
Creating Tests/
$ swift build //編譯並生成可執行的二進制文件
Compile Swift Module 'SPMDemo' (1 sources)
Linking ./.build/debug/SPMDemo
$ swift run //執行生成的文件
Hello, world! //執行效果
複製代碼
二、加入依賴包xcode
咱們須要在前面建立的包中使用第三方庫(這裏以SwiftyJSON爲例),編輯Package.swift文件:bash
// 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: "SPMDemo",
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "4.0.0"), //第三方庫url和版本號
],
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: "SPMDemo",
dependencies: ["SwiftyJSON"]), //依賴的包名稱
]
)
複製代碼
注:關於dependencies的格式定義能夠看這裏有詳細說明文檔,能夠指定分支、具體的commit編號、版本範圍等等。app
而後咱們檢驗一下引入的依賴包是否可用,編輯Sources目錄下的main.swift文件:工具
import SwiftyJSON //引入模塊
let json = JSON(["name":"Jack", "age": 25])
print(json)
print("Hello, world!")
複製代碼
保存以後咱們再run一下:ui
$ swift run
Fetching https://github.com/SwiftyJSON/SwiftyJSON.git
Cloning https://github.com/SwiftyJSON/SwiftyJSON.git
Resolving https://github.com/SwiftyJSON/SwiftyJSON.git at 4.0.0
Compile Swift Module 'SwiftyJSON' (1 sources)
Compile Swift Module 'SPMDemo' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/SPMDemo
{
"name" : "Jack",
"age" : 25
}
Hello, world!
複製代碼
能夠看到輸出了咱們的json結構體,說明引入依賴包成功了!
注:第一次run的時候SPM會先將依賴的庫克隆下來並編譯好放在.build隱藏文件夾中,若是把這個文件夾刪除從新run,會從新下載。
三、如今咱們來試試本身定義一個庫做爲其餘項目的依賴包
$ mkdir MyLib
$ cd MyLib
$ swift package init //初始化包,不帶參數的話默認是Library
Creating library package: MyLib
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/MyLib/MyLib.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/MyLibTests/
Creating Tests/MyLibTests/MyLibTests.swift
複製代碼
建立Library的話默認是沒有main.swift文件的,Sources目錄下只有一個MyLib.swift文件,它給咱們定義了一個結構體,但並非public的,咱們知道swift中只有被public和open修飾才能被其餘模塊訪問,因此咱們把它改爲public:
public struct MyLib {
var text = "Hello, MyLib!"
public var num:Int
public init() {
num = 2
}
}
複製代碼
而後咱們build一下,確保咱們的Library能順利編譯經過。
由於SPM依賴包必須使用git url和版本號,因此咱們須要爲咱們的庫建立一個git倉庫並提交代碼和打tag:
$ git init
$ git add .
$ git commit -m "Initial Commit"
$ git tag 1.0.0
複製代碼
接下來修改前面的Package.swift文件,加入咱們的Library:
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "4.0.0"),
.package(url: "./MyLib", from: "1.0.0") //由於沒有推送到遠程倉庫,因此這裏用相對路徑,from就是咱們剛纔打的tag
],
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: "SPMDemo",
dependencies: ["SwiftyJSON","MyLib"]), //添加依賴包名
]
複製代碼
而後咱們再檢驗一下依賴包是否可用,編輯main.swift文件:
import SwiftyJSON
import MyLib
//SwiftyJSON
let json = JSON(["name":"Jack", "age": 25])
print(json)
//自定義庫
let lib = MyLib()
print(lib)
複製代碼
而後咱們再run一次看看:
{
"name" : "Jack",
"age" : 25
}
MyLib(text: "Hello, MyLib!」, num: 2) 複製代碼
結果輸出了咱們自定義的庫中結構體的內容,說明咱們引入自定義依賴包成功了!
除了macOS之外,目前SPM不支持蘋果其餘平臺,因此若是想替換Pods或者Carthage仍是謹慎一點,等蘋果徹底支持iOS之後再切換過來吧。不過咱們能夠以引入子工程的方式在iOS項目中使用SPM,具體步驟以下:
一、建立新的iOS項目或者使用已存在的項目
二、將該工程初始化爲SPM(swift package init)
三、建立一個空的依賴源文件和路徑,由於建立xcodeproj文件的時候須要至少一個源文件,這裏我在dep-sources路徑下建立一個Dependencies.swift文件:
$ mkdir dep-sources
$ cd dep-sources/
$ touch Dependencies.swift
複製代碼
四、修改Package.swift文件,加入依賴庫並設置target爲新的名字,不然會跟iOS工程的target重名,這裏我改成Dependencies,而後在target中設置第3步的路徑
// 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: "Dependencies",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "Dependencies",
type: .static,
targets: ["Dependencies"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "4.0.0"),
.package(url: "https://github.com/Alamofire/Alamofire.git", from: "4.6.0")
],
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: "Dependencies",
dependencies: ["SwiftyJSON","Alamofire"],
path: "dep-sources" //源文件路徑
)
]
)
複製代碼
五、執行swift package generate-xcodeproj命令,這裏會生成Dependencies.xcodeproj
$ swift package generate-xcodeproj
Fetching https://github.com/SwiftyJSON/SwiftyJSON.git
Fetching https://github.com/Alamofire/Alamofire.git
Cloning https://github.com/SwiftyJSON/SwiftyJSON.git
Resolving https://github.com/SwiftyJSON/SwiftyJSON.git at 4.0.0
Cloning https://github.com/Alamofire/Alamofire.git
Resolving https://github.com/Alamofire/Alamofire.git at 4.6.0
generated: ./Dependencies.xcodeproj
複製代碼
六、打開iOS工程,將第5步生成的project拖入工程做爲sub-project,而後添加依賴的framework就能夠了(xcode9常常莫名其妙抽風,建議作完後關閉從新打開工程)
七、驗證引入包是否成功
一、no such module
$ swift build
Compile Swift Module 'SPMDemo' (1 sources)
/SPMDemo/Sources/SPMDemo/main.swift:2:8: error: no such module 'MyLib'
import MyLib
複製代碼
這有多是你只加入了依賴包的路徑而沒有在target中加入模塊名稱
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: "SPMDemo",
dependencies: ["SwiftyJSON"]), //缺乏「MyLib」
]
複製代碼
還有一種狀況是更新了依賴包,可是沒有構建到.build目錄下,這個時候只要把.build文件刪除,從新構建一次就能夠了。有什麼問題歡迎留言討論!