WWDC 2018 Session 411: Getting to Know Swift Package Managerhtml
查看更多 WWDC 18 相關文章請前往 老司機x知識小集xSwiftGG WWDC 18 專題目錄git
做者:KANGZUBINgithub
目前,在 macOS/iOS 開發中,咱們一般使用 CocoaPods 或 Carthage 等非官方工具來管理項目工程中對第三方開源庫的依賴。shell
Swift Package Manager(Swift 包管理器,通常簡稱 SwiftPM 或者 SPM)是蘋果官方提供的一個用於管理源代碼分發的工具,旨在使分享代碼和複用其餘人的代碼變得更加容易。該工具能夠幫助咱們編譯和連接 Swift packages(包),管理依賴關係、版本控制,以及支持靈活分發和協做(公開、私有、團隊共享)等。swift
SwiftPM 於 2016 年隨 Swift 3.0 一塊兒發佈,已經兩年多了,今年 WWDC 2018 專門開了一個 Session 用來介紹如何使用它,咱們一塊兒來了解一下吧。xcode
目前已經有不少優秀包管理器用於分享和複用代碼,對於爲何要爲 Swift 專門開發一個新的包管理工具(Why a new package manager for Swift?),蘋果的工程師在該 Session 中主要總結了以下幾個理由:安全
首先,Swift 是一個跨平臺開發語言,因此咱們須要一個強大的跨平臺工具用於構建 Swift 代碼,它能夠用一致的方式輕鬆配置代碼,而後在 Swift 所支持的全部平臺上運行。SwiftPM 包含其本身的完整構建系統,使你可以僅在一個工具中完成代碼的編譯、測試和運行等。bash
蘋果但願在 Swift 項目中提供一個官方權威統一規範的包管理器,經過定義一個分發 libraries(庫)的通用標準,讓咱們儘量方便地在 Swift 生態系統中與他人分享 Swift libraries(庫)。併發
在開發過程當中,核心標準庫有時候不能知足咱們的需求,咱們可能會想擴展它,但爲了保證核心庫 API 的簡潔,不可能隨意往裏添加內容。所以,有一個強大的包管理器就能夠很容易地將這些擴展做爲 package 來分發和共享,而沒必要將它們放到核心庫中,而那些好的擴展能夠隨着時間的推移持續地得到社區的支持而且變得愈來愈標準化。app
SwiftPM 自己是用 Swift 編寫的,它能夠充分利用 Swift 的強大功能和設計理念,經過與 Swift 語言和核心庫項目密切合做,能夠建立出更加出色的包管理器功能。
SwiftPM 是 Swift 開源項目中的一部分,它被包含在每一個 Swift 工具鏈中,同時它也包含在 Xcode 的每一個 Release 版本中,你能夠很方便地使用它。
一個 package(包)由 Swift 源碼文件和一個清單文件組成。這個清單文件被稱爲 Package.swift
,它使用 PackageDescription
模塊來定義包的名稱和內容。一個包一般有一個或者多個 targets(目標),每一個 target 指定一個 product(產品)並聲明一個或者多個 dependencies(依賴)。
在 package(包)中的每個 target(目標)最終可能構建成一個 library(庫)或者一個 executable(可執行文件)做爲其 product(產品)。庫是包含能夠被其餘 Swift 代碼引用的模塊,可執行文件是一段能夠被操做系統運行的程序。
對於 SwiftPM 的一些基本概念,例如:Modules、Packages、Products、Dependencies、Targets 等,在 Swift.org 官網已經有很是詳細的描述和定義,另外,也能夠參見《Swift Package Manager 快速入門指引》這篇文章的翻譯,咱們這裏再也不贅述。
如上文所述,Swift Package Manager 提供了一個完整的系統用於構建 libraries(庫)和 executables(可執行文件),以及能夠跨不一樣 packages(包)共享代碼,下面咱們來介紹一下如何使用 SwiftPM。
swift build: 用於編譯 package
swift run: 用於編譯並運行一個可執行文件,該命令是在 Swift 4 中新增長的,詳見這個提案,它至關於:
$ swift build
$ .build/debug/myexecutable
複製代碼
swift test: 用於運行 package 中的單元測試
swift package: 在 package 中進行各類除編譯/運行/測試以外的操做,如建立、編輯、更新、重置、修改編譯選項/路徑等
此外,你能夠在命令行中執行 swift package --version
查看當前 SwiftPM 的版本:
$ swift package --version
Apple Swift Package Manager - Swift 4.1.0 (swiftpm-14050)
複製代碼
也能夠執行 swift package --help
查看關於命令的更多幫助。
關於上述 4 個基本命令的使用和更多信息,能夠查閱官方使用示例和文檔。
$ mkdir helloword // 建立 helloword 文件夾
$ cd helloword // 進入 helloword 文件夾
$ swift package init --type executable // 在當前文件下初始化 package 爲可執行項目
$ swift run // 編譯並執行
Hello, world!
複製代碼
執行 swift package init --type executable
命令後,在 helloword
文件夾中會自動生成以下目錄和文件:
此外,你也能夠在當前文件夾下執行 swift package generate-xcodeproj
命令生成一個 Xcode 工程,例如:
$ mkdir MyPackage
$ cd MyPackage
$ swift package init # or swift package init --type library
$ swift build
$ swift test
複製代碼
若是你的 package 須要依賴於其它 package,你只須要在 Package.swift
配置清單文件中添加依賴的 GitHub URL 和對應的版本號(關於版本號的規則,下文會詳細講)便可:
import PackageDescription
let package = Package(
name: "MyPackage",
dependencies: [
// 添加依賴包:PlayingCard
.Package(url: "https://github.com/apple/example-package-playingcard.git", from: "3.0.0"),
]
)
複製代碼
接下來你就能夠在當前 package 中的任何源文件中 import PlayingCard
,並調用它的公開 APIs。
同時,你也能夠經過修改 Package.swift
文件中相關依賴的版本號,並執行 swift package update
命令來更新依賴包。
一個 package 一般就是一個的 git 倉庫,並經過標籤語義來表示版本(versioned tags)
所以,若是要對外發佈一個 package,你只要在你的 git 倉庫中添加一個用於表示版本號的標籤(如 tag 1.0.0),便可提交到 GitHub 上對外發布:
$ git init
$ git add .
$ git remote add origin [github-URL]
$ git commit -m "Initial Commit"
$ git tag 1.0.0
$ git push origin master --tags
複製代碼
執行上述命令後,其餘 package 就能夠經過 GitHub URL 依賴此 package 的當前版本(1.0.0)。
你也能夠參考蘋果發佈的 package 示例:example-package-fisheryates
一個 package 主要由以下三個部分組成,它們的概念咱們前面已經介紹過:
Dependencies / 依賴
Targets / 目標
Products / 產品
一個常見的 Package.swift
配置文件內容大體以下:
其中,targets 是 package 的基本組成部分,它描述瞭如何將一組源文件構建成模塊或測試用例,一個 target 能夠依賴於當前 package 中的其它 target,也能夠依賴於聲明爲依賴關係的其餘 package 所導出的 product(產品)。
例如上述 package 中聲明依賴了一個外部 package,名字爲 DeckOfPlayingCards
,其版本爲大於等於 3.0.0
,且 libdealer
target 依賴於該外部產品 DeckOfPlayingCards
,而 dealer
則依賴於本身 package 中的 libdealer
,最後 dealerTests
依賴於前面這兩個 targets,用於對 package 相關功能進行單元測試。
另外,在該文件中定義了兩個 products,分別爲 libdealer
和 dealer
,它們與 targets 相對應,通常由一個或多個 targets 組成,並最終將被分別構建成 library(庫)和 executable(可執行文件)。
Swift Package Manager 是 Swift 開源項目中的一部分,遵循 Swift 的理念:
Safe: 安全,隔離的構建環境
Fast: 快速,可擴展到大型依賴關係圖
Expressive: 有表現力的,使用 Swift 語言定義 manifest 配置文件的格式
經過 SwiftPM 構建一個 package 主要包括以下幾個步驟:
如上所述,SwiftPM 使用 Swift 語言來編寫其配置清單的格式,容易理解,無需額外的學習成本,其遵循Swift API 設計準則,能夠獲得現有的 Swift 工具的支持。
蘋果推薦在 Package.swift
中優先使用明確的語義,而少用變量替換和拼接,方便本身維護和用戶更直觀地閱讀和理解:
SwfitPM 會自動包含磁盤上當前 package 中 Sources 目錄中的源文件,且 Sources 目錄下的各子文件夾中的代碼會自動與同名的 target 關聯,而不須要在清單文件中顯式聲明:
此外,它也支持編譯其餘語言,如 C/C++/Objective-C 等,可是目前不支持將這些語言與 Swift 混合編譯放在同一個 target 中,須要分別放在不一樣的 target。
SwiftPM 採用語義化版本來控制依賴的版本,規則以下:
版本格式:主版本號.次版本號.修訂號,版本號遞增規則爲:
例如:.exact("0.2.1")
指定某一個具體的版本,from: "3.0.0"
指定獲取大於等於 3.0.0
(但小於 4.0.0
)的最新版本,tag 3.1.4
指定獲取某一標籤,upToNextMinor(from: "1.5.8")
獲取指定版本到下一個次版本號(即 1.5.8
~ 1.6.0
)之間的最新版本。
此外,packge 之間的依賴是能夠傳遞的(遞歸),好比 A 依賴了 B,B 依賴了 C,那麼 A 固然也自動會依賴於 C:
此外,SwiftPM 一樣使用一個 Package.resolved
文件用於記錄已經解析安裝的 packages 版本,相似於 CocoaPods 中的 Podfile.lock
或 Carthage 中的 Cartfile.resolved
。
它能夠用於共享可靠的編譯結果,且易於進行新版本更新,但僅適用於頂層(top-level)的 package,例如上圖中的 dealer
。
SwiftPM 使用 llbuild
做爲其底層編譯引擎,提供快速和正確的增量編譯,它也被 Xcode 新的編譯建系統使用,是 Swift 開源項目的一部分。
SwiftPM 進行構建 package 的編譯環境是在一個沙盒中被隔離獨立的,沒法隨意執行命令或 shell 腳本,所以保證了其安全性。同時也支持基於 XE.framework 單元測試,併發測試,或者指定測試某些場景(Test Filtering)等。
SwiftPM 提供了很是靈活的工做流程,你可讓你的 package 依賴於某一處於編輯模式(Edit Model)的 package(把某一遠程 package 下載到本地臨時目錄進行編輯),方便你進行調試。你也能夠指定依賴 package 的某一分支或者標籤,進行特定的功能測試。同時,它也容許你依賴本地的 Package(Local Package Dependencies)。
每一個 Package 中的 API 能夠隨 Swift 的新版本進行更新,但之前的 API 仍然可用,SwiftPM 容許在不更新清單的狀況下使用新的 Swift 工具。
由於咱們能夠在 Package.swift
清單文件中指定工具版本和語言版本。以下圖所示,第一行註釋用於指定 Swift 工具最低版本號,第二行用於指定該 package 中代碼使用 Swift 語言版本,便於編譯,它是一個列表,能夠接受多個版本號。
本節簡要介紹一下 Session 中提到的 SwiftPM 即將支持的一些新特性。
SwiftPM 官方的提供庫 libSwiftPM
如今已經可用,蘋果鼓勵開發人員能夠基於這個庫爲 SwiftPM 開發一些擴展工具,如:
Idea: Machine-Editable Package.swift,基於 libSyntax
庫,當用戶在編輯 Package.swift
時,能夠自動根據用戶的輸入,預生成相應配置代碼。
Idea: 標籤和發佈支持,目前 SwiftPM 的 package 依賴於 git 的標籤來發布版本,流程比較繁瑣,後續工具自己將添加新功能來簡化並自動執行此過程。
Idea: 自動進行語義版本增長
Idea: 部署自動化
Idea: 支持圖片等資源文件(Resources)
Idea: 支持編譯設置(Build Settings)
Idea: 可擴展的編譯工具,自動根據源文件的代碼註釋和相關配置,生成二進制文件及其使用文檔
Idea: Package 內容的校驗,防止被篡改
Idea: 跨平臺的沙箱隔離(Cross-Platform Sandboxing)
Idea: 支持 Fork 操做
Idea: 支持建立 Package 索引,提高搜索速度
更多關於 SwiftPM 的將來新特性,能夠在 swift-evolution 中找到更加詳細的描述,你也能夠在上面提交 proposals 貢獻你的想法。
你能夠經過如下幾個渠道關注或參與 Swift 和 SwiftPM 等項目的進展:
https://swift.org/package-manager/
https://github.com/apple/swift-evolution
https://forums.swift.org/c/development/SwiftPM
https://bugs.swift.org
https://ci.swift.org
https://swift.org/download/#snapshots
https://github.com/apple/swift-package-manager
此外,隨着 Swift 的發展,SwiftPM 在服務端(Server-Side Swift)開發和命令行工具(Command-Line Utilities)開發中也有愈來愈普遍的應用。
去年 Swift 4 發佈時,咱們整理翻譯了 swift-evolution 中新增的 Package Manager 相關的部分提案(proposals),詳見:
後續咱們會繼續翻譯 swift-evolution 中的其餘新提案,歡迎和咱們一塊兒完善。
講真,當看到 WWDC 2018 時間表中這個 Swift Package Manager 相關的 Session 時,我是很興奮,感受它應該能夠支持 iOS 開發了吧?
可是,等到大會結束時,我看到 GitHub 上 swift-package-manager 項目的 README 描述中,仍然保留着這句話:
Note that at this time the Package Manager has no support for iOS, watchOS, or tvOS platforms.
很遺憾,目前 Swift Package Manager 仍然僅支持在 macOS、Linux 開發中使用,並不支持 iOS/watchOS/tvOS 等平臺,也許在 Swift 5 發佈之後就能支持了吧?讓咱們一塊兒期待吧。