Swift packages 是可重複使用的程式碼元件。它可包含程式碼、二進位檔、和資源檔。我們可以很容易地在我們的 app 專案中使用 Swift packages。本文章將介紹如何建立並發佈 Swift packages。
Table of Contents
建立 Swift Packages
有兩種方式可以建立 Swift packages。一種是使用 Xcode,另一種是使用 command line。
用 Xcode 建立 Swift Packages
Xcode 支援建立、發佈、和管理 Swift packages。使用 Xcode 建立 Swift packages 是相當簡單的。打開你的 Xcode,選擇 File -> New -> Package。
Xcode 會跳出下面的視窗,要求你輸入 Swift package 的名稱,以及選擇儲存的路徑。我們輸入 Greeting 作為我們的 Swift package 的名稱。
按下 Create 之後,Xcode 會產生一個 Swift package,如下圖。一個標準的 Swift package 包含一個 Package.swift、Sources 資料夾、和 Tests 資料夾。
- Package.swift:Swift package 的配置檔。我們之後會詳細地介紹它。
- Sources/:資料夾下有一個和此 Swift package 名稱一樣的資料夾叫 Greeting。所有的程式碼都應該在這下面。
- Tests/:資料夾下有一個資料夾,其名稱是此 Swift package 名稱加上 Tests。所有的測試程式碼都應該在這下面。
用 Command Line 建立 Swift Packages
使用 command line 來建立 Swift packages 也是很容易的。首先先建立一個資料夾,其名稱將會是 Swift package 的名稱。然後,在此資料夾下,輸入 swift package init --type library
,它會產生 Swift package 專案。
% mkdir Greeting % cd Greeting Greeting % swift package init --type library Creating library package: Greeting Creating Package.swift Creating README.md Creating .gitignore Creating Sources/ Creating Sources/Greeting/Greeting.swift Creating Tests/ Creating Tests/GreetingTests/ Creating Tests/GreetingTests/GreetingTests.swift
Package.swift
Package.swift 是 Swift package 的配置檔。它裡面主要的使用一個 Package 物件來定義所有的配置。
Package.swift 的第一行永遠是定義此 Swift package 要使用的 Swift tool 版本號。使用 5.4 和之後的版本的話,可以在前面加上空白,也可以不加。但是使用 5.3 和之前的版本的話,則前面不可以加上空白。
Swift tool 版本定義了:
- PackageDescription library 的版本。
- Swift tools 和 Swift 相容語言的最低版本。它們之後會用來執行此配置檔。
- 要使用此 Swift package 時,所需最低版本的 Swift tools。
// swift-tools-version: 5.4
Package 的建構子如下。其有不少參數,我們將只介紹幾個常用的參數。
Package.init( name: String, defaultLocalization: LanguageTag? = nil, platforms: [SupportedPlatform]? = nil, pkgConfig: String? = nil, providers: [SystemPackageProvider]? = nil, products: [Product] = [], dependencies: [Package.Dependency] = [], targets: [Target] = [], swiftLanguageVersions: [SwiftVersion]? = nil, cLanguageStandard: CLanguageStandard? = nil, cxxLanguageStandard: CXXLanguageStandard? = nil )
name 定義此 Swift package 的名稱。
platforms 列出此 Swift package 支援的 platforms。SupportedPlatform 定義了所有可選用的 platforms。
products 列出此 Swift package 最後會產生的 products。當其他的 Swift package 使用此 Swift package 時,會看到的 product 列表。Product 定義了三種 products:
- .library(name:type:targets):產生出一個 library。整合此 library 的 Swift packages 可以使用其 public APIs。
- name:此 library product 的名稱。
- type:決定整合此 library 的 Swift packages 該如何 link 此 library。若不指定此參數,則 Swift Package Manager 可根據整合此 library 的 Swift packages 的偏好設定來決定。
- targets:定義此 library product 是由哪些 targets 產生的。這些 targets 是定義在 Package.init() 裡的 targets 參數。
- .executable(name:targets:):產生出一個 executable。
- .plugin(name:targets:):產生出一個 Swift package plugin。
dependencies 列出此 Swift package 所倚賴列表。Package.Dependency 定義一個依賴的來源與版本。
- package(path:):從給定的 path,加入一個 local package 作為依賴。
- package(url:from:):從給定的 url,加入一個 remote package 作為依賴。其版本可從指定的最低版本至下一個 major 版本。
targets 列出此 Swift package 會產生出的 targets。與 products 不同的是,一個 product 是由一個或數個 targets 一起 bundle 而成的。Target 定義一個 target。
- .target(name:dependencies:):建立一個 library target。
- name:此 target 的名稱。
- dependencies:指定此 target 依賴其他的 targets。如果此 target 依賴一個定義在 Package.init() 的 dependencies 的話,也必須要在這邊指定。
- .testTarget():建立一個 test target。
- .binaryTarget():建立一個 binary target。這個 target 會參考到 path 所指的 binary artifact。
- .systemLibrary():建立一個 system library target。
- .executableTarget():建立一個 executable target。
- .plugin():建立一個 package plugin target。
以下是 Greeting package 的 Package.swift。我們在 dependencies 中加入一個依賴叫 SwiftyJSON。然後,在 targets 中,我們也要指名 target Greeting 依賴於 SwiftyJSON。
// swift-tools-version: 5.7 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Greeting", platforms: [ .iOS(.v13) ], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "Greeting", targets: ["Greeting"]), ], 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"), ], 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 this package depends on. .target( name: "Greeting", dependencies: ["SwiftyJSON"]), .testTarget( name: "GreetingTests", dependencies: ["Greeting"]), ] )
發佈 Swift Packages
發佈 Swift packages 給其他的 Swift packages 使用是很簡單的。我們只要將我們的 Swift package 放到一個 Git repository,那其他的 Swift packages 就可以透過這個 Git repository 的 URL 來我們的 Swift package 整合進專案裡。至於版本的話,我們可以透過 Git tag 來標注版本。
以上的發佈流程可以使用 Xcode、command line、或是任何 Git client app 來做。
用 Xcode 發佈 Swift Packages
點選 Source Control -> New Git Repository。
選擇為當前的 Swift package 創建 Git repository。
這時候目前 Swift package 的 Git repository 已經創建好了。Xcode 也為我們建立了第一筆 commit。
在右邊的 Navigator 上,點選 Show the source control navigator,並選擇 Repositories。然後在 Remotes 上點擊右鍵,並選擇 New “Greeting” Remote..。
這時 Xcode 會彈出下面的視窗。我們在 Account 欄位選擇 GitHub。它會要求我們輸入 GitHub 的 Account 和 Token 來登入 GitHub。
輸入好 GitHub 的 Account 和 Token 後,我們就可以在 GitHub 上建立一個 remote repository。值得注意的是,repository name 最好和我們的 Swift package 的名稱一樣,也就是 Greeting。
Xcode 幫我們建立好一個 remote repository 時,會順便 push 所有的 local commits 到 remote repository。
接下來,我們要建立一個 Git tag 來發佈版本 1.0.0。在我們最後一筆的 commit 上點擊右鍵,選擇 Tag “xxxxxxx”,其中 xxxxxxx 會被取代為該 commit 的 hash。
Xcode 會彈出以下視窗。我們輸入 tag 的名稱,也就是 1.0.0。
當建立好 Git tag 時,這個 Git tag 還只有在 local 而已。我們需要將它 push 到 remote repository。選擇 Source Control -> Push。
Xcode 會彈出以下視窗。務必點選 Include tags,然後點擊 Push 按鈕。這樣就完成發佈版本 1.0.0。
用 Command Line 發佈 Swift Packages
如果你的 Swift package 還不是 Git repository 的話,必須先用以下的指令在你的 Swift package 下建立一個 Git repository。
% cd Greeting Greeting % git init Initialized empty Git repository in /Users/wayne/Greeting/.git/ Greeting % git add . Greeting % git commit -m "first commit" [main (root-commit) 916bcf6] first commit 5 files changed, 57 insertions(+) create mode 100644 .gitignore create mode 100644 Package.swift create mode 100644 README.md create mode 100644 Sources/Greeting/Greeting.swift create mode 100644 Tests/GreetingTests/GreetingTests.swift Greeting % git branch -M main
然後,在任何 Git hosting 中建立一個 Git repository。這個 Git repository 的名稱、Swift package 資料夾的名稱、和 Swift package 的名稱,三者最好都相同。在以下指令中,我們把 Swift package 送到 https://github.com/xhhuango/Greeting.git。
Greeting % git remote add origin https://github.com/xhhuango/Greeting.git Greeting % git push -u origin main Enumerating objects: 11, done. Counting objects: 100% (11/11), done. Delta compression using up to 16 threads Compressing objects: 100% (6/6), done. Writing objects: 100% (11/11), 1.41 KiB | 1.41 MiB/s, done. Total 11 (delta 0), reused 0 (delta 0), pack-reused 0 To github.com:xhhuango/Greeting.git * [new branch] main -> main branch 'main' set up to track 'origin/main'.
最後,我們用 Git tag 新增一個 1.0.0 的 tag,並將 tag 送到 remote Git repository。這樣就完成發佈版本 1.0.0。
Greeting % git tag 1.0.0 Greeting % git push origin --tags Total 0 (delta 0), reused 0 (delta 0), pack-reused 0 To github.com:xhhuango/Greeting.git * [new tag] 1.0.0 -> 1.0.0
加入 Swift Package 依賴
當發佈好我們的 Swift package 後,你就可以在你的 Xcode projects 中加入剛剛發佈的 Swift package。下面文章將詳細地介紹如何在你的 Xcode projects 中加入 remote 或 local Swift packages。
結語
Swift packages 是可重複使用的程式碼元件。與以往的 Xcode projects 不同的是,它不需要 Xcode 的專案檔,而是使用 Package.swift 來配置 Swift packages。比起 Xcode 的專案檔,Package.swift 清楚且簡單許多。
參考
- Creating a standalone Swift package with Xcode, Apple Developer.
- Publishing a Swift package with Xcode, Apple Developer.