Now that we have learned the basics of using SPM to create a simple library, let's have a look at how to work with external dependencies. So, let's add one to our package. For this example, we will work with Google Promises, which we covered in Chapter 12, Futures, Promises, and Reactive Programming. So, open Package.swift in your preferred editor and make sure the dependencies section looks like this (the text you should add is in bold):
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/google/promises.git", .exact("1.2.3")),
],
After saving the file, run swift package resolve to get the dependency installed under .build/repositories/:
Fetching https://github.com/google/promises.git
Completed resolution in 1.81s
Cloning https://github.com/google/promises.git
Resolving https://github.com/google/promises.git at 1.2.3
The swift package resolve command also creates a Package.resolved file in your package root, which contains a list of all installed dependencies along with their repository URL, version, and commit hash. If you want to get a shortened version of the same information, just run swift package show-dependencies, which will show the following:
warning: dependency 'Promises' is not used by any target
.
└── Promises<https://github.com/google/promises.git@1.2.3>
Now, we could import Promises in our executable main.swift file and refactor our code to use that library. Instead, we will leave that as an exercise to the reader and will focus on another important feature in SPM: its ability to automatically update dependencies when new versions are available.
In our current example, we pinned Google Promises down to version 1.2.3. Say we now want to remove that restriction and accept any version of that library starting with 1.2.3. To do that, we modify our Package.swift dependency section to look like this, where we replaced .exact("1.2.3") with from:"1.2.3":
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/google/promises.git", from: "1.2.3"),
],
After that, whenever you want to make SPM update your package dependencies, just run swift package update:
$ swift package update
Updating https://github.com/google/promises.git
Completed resolution in 1.14s
Resolving https://github.com/google/promises.git at 1.2.4
Besides specifying the exact version you want to use, or a starting version, SPM supports a number of additional possibilities:
.package(url: "https://github.com/google/promises.git",
.upToNextMajor(from: "1.2.3")),
.package(url: "https://github.com/google/promises.git",
.upToNextMinor(from: "1.2.4")),
.package(url: "https://github.com/google/promises.git",
"1.2.3"..<"1.2.6"),
.package(url: "https://github.com/google/promises.git",
"1.2.3"..."1.2.8"),
.package(url: "https://github.com/google/promises.git",
.branch("develop")),
.package(url: "https://github.com/google/promises.git",
.revision("e74b07278b926c9ec6f9643455ea00d1ce04a021"))
This is all great! But let's see how we can leverage SPM in a workflow aimed at the creation of a full-fledged iOS or macOS app written in Xcode.