Swift packages are reusable code components. It can contain code, binaries, and resource files. We can easily use Swift packages in our app projects. This article describes how to build and publish Swift packages.
The complete code for this chapter can be found in .
Table of Contents
Creating Swift Packages
There are two ways to create Swift packages. One is using Xcode and the other is using the command line.
Creating Swift Packages with Xcode
Xcode supports creating, publishing, and managing Swift packages. Creating Swift packages with Xcode is fairly simple. Open your Xcode, select File -> New -> Package.
Xcode will pop up the following dialog, asking you to enter a name for your Swift package and choose the path to store the Swift package. We enter Greeting as the name of our Swift package.
After clicking Create button, Xcode will generate a Swift package, as shown below. A standard Swift package contains a Package.swift, Sources folder, and Tests folder.
- Package.swift: Configuration file for the Swift package. We will explain it in detail later.
- Sources/: Under this folder, there is a folder named Greeting with the same name as this Swift package. All code should go under here.
- Tests/: Under this folder, there is a folder whose name is the name of the Swift package plus Tests. All test code should go under here.
Creating Swift Packages with the Command Line
It’s also easy to create Swift packages using the command line. First create a folder whose name will be the name of this Swift package. Then, under this folder, enter swift package init --type library
, which will generate a Swift package project.
% 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 is the configuration file for a Swift package. It mainly uses a Package object to define all configurations.
The first line of Package.swift is always the version number of the Swift tool that defines this Swift package to use. For version 5.4 and later, you may or may not have a leading blank. However, if you use 5.3 and earlier version, you cannot add blanks in front of it.
The Swift tool version defines:
- Version of the PackageDescription library.
- A minimum version of the Swift tools and Swift language compatibility version. They will then be used to process the manifest.
- The required minimum version of Swift tools to use this Swift package.
// swift-tools-version: 5.4
The constructor of Package is as follows. It has many parameters, we will only explain a few commonly used parameters
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 )
The name defines the name of this Swift package.
The platforms lists the platforms supported by this Swift package. SupportedPlatform defines all available platforms.
The products lists the final products that this Swift package vends. When other Swift packages use this Swift package, they will see the list of products. Product defines three products:
- .library(name:type:targets) : Create a library. Swift packages that integrate this library can use its public APIs.
- name: The name of this library product.
- type: Determine how the Swift packages that integrate this library should link this library. If this parameter is not specified, the Swift Package Manager can decide based on the preferences of the Swift packages integrating this library.
- targets: Define targets to vends as this product. These targets are defined in the targets parameter of Package.init().
- .executable(name:targets:) : Create an executable.
- .plugin(name:targets:) : Create a Swift package plugin.
The dependencies list the dependencies of this Swift package. Package.Dependency defines the source and version of a dependency.
- package(path:) : From the given path, add a local package as a dependency.
- package(url:from:) : From the given url, add a remote package as a dependency. Its version can be from the specified minimum version to the next major version.
The targets lists the targets that this Swift package will produce. Different from products, a product is bundled of one or several targets. Target defines a target.
- .target (name:dependencies:) : Create a library target.
- name: The name of this target.
- dependencies: Specifies that this target depends on other targets. If this target depends on a dependencies defined in Package.init(), it must also be specified here.
- .testTarget() : Create a test target.
- .binaryTarget() : Create a binary target. This target refers to a binary artifact pointed to the given path.
- .systemLibrary() : Create a system library target.
- .executableTarget() : Create an executable target.
- .plugin() : Create a package plugin target.
Below is the Package.swift of the Greeting package. We add a dependency called SwiftyJSON to dependencies. Then, in targets, we also specify that the target Greeting depends on 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"]), ] )
Publishing Swift Packages
Publishing Swift packages for use by other Swift packages is easy. We only need to put our Swift package into a Git repository, then other Swift packages can integrate our Swift package into the project through the URL of this Git repository. As for the version, we can add a version through Git tag.
The above publishing process can be done using Xcode, the command line, or any Git client app.
Publishing Swift Packages with Xcode
Click Source Control -> New Git Repository.
Choose the current Swift package to create a Git repository.
At this time, the Git repository of the current Swift package has been created. Xcode also created the first commit for us.
On the Navigator, click Show the source control navigator, and select Repositories. Then right click on Remotes and select New “Greeting” Remote..
At this point Xcode will pop up the following dialog. We select GitHub in the Account field. It then asks us to enter GitHub’s Account and Token to log in to GitHub.
After entering the GitHub Account and Token, we can create a remote repository on GitHub. It is worth noting that the repository name should preferably be the same as the name of our Swift package, which is Greeting.
When Xcode creates a remote repository for us, it also push all the local commits to the remote repository.
Next, we’re going to create a Git tag to release version 1.0.0. Right-click on our last commit and select Tag “xxxxxxx”, where xxxxxxx will be replaced with the commit hash.
Xcode will pop up the following dialog. We enter the name of the tag, which is 1.0.0.
When the Git tag is created, the Git tag is only local. We need to push it to the remote repository. Select Source Control -> Push.
Xcode will pop up the following dialog. Be sure to check “Include tags”, then click the Push button. This completes the release version 1.0.0.
Publishing Swift Packages with the Command Line
If your Swift package is not a Git repository, you need to first use the following command to create a Git repository under your Swift package.
% 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
Then, create a Git repository on any Git hosting. The name of the Git repository, the name of the Swift package folder, and the name of the Swift package should preferably all be the same. In the following command, we send the Swift package to 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'.
Finally, we use Git tag to add a tag named 1.0.0 and send the tag to the remote Git repository. This completes the release version 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
Adding Swift Package Dependencies
After publishing our Swift package, you can add the newly released Swift package to your Xcode projects. The following article will detail how to add remote or local Swift packages to your Xcode projects.
Conclusion
Swift packages are reusable code components. Unlike Xcode projects, it does not require Xcode project files, but uses Package.swift to configure Swift packages. Compared to Xcode’s project files, Package.swift is much clearer and simpler.
References
- Creating a standalone Swift package with Xcode , Apple Developer.
- Publishing a Swift package with Xcode , Apple Developer.