Xcode provides powerful tools for organizing and reusing code through frameworks and packages. While frameworks offer a way to bundle code, resources, and assets into a reusable module, the Swift Package Manager (SPM) simplifies the process of sharing and integrating Swift code. This guide will cover the basics of frameworks and packages in Xcode and provide step-by-step instructions on creating your own Swift package library that you can upload to GitHub for public or private use.
Frameworks and Packages: What’s the Difference?
In Xcode, frameworks and packages help modularize code, making it reusable and easy to maintain. Here’s a quick overview:
- Frameworks: A framework is a bundle containing compiled code and resources that developers can reuse across different apps. Common frameworks include UIKit and Foundation. In iOS, developers often create frameworks to encapsulate complex functionality for specific features.
- Packages: Swift Packages are collections of Swift code managed by the Swift Package Manager. Packages can be shared, versioned, and integrated with projects easily. With the growing popularity of SPM, creating packages is now a standard way to distribute reusable code in the Swift community.
Creating Your Own Swift Package
For this example, we are going to create a package that will contain a Networking Client that we could import and use in all of our new projects:
Step 1: Create a New Swift Package
- Open Xcode and select File > New > Package.
- Select Library
- Select the test system you'd like.
- Give your package a name. This will be the name others will use to import it, so choose a name that reflects its functionality.
- Choose a location to save your package, then click Create. Xcode will create a new folder containing the package’s structure, including the
Package.swift
file.
The Package.swift
file is the package’s manifest file, which defines the package name, its dependencies, targets, and other metadata. It’s automatically created with default values.
Step 2: Define Your Package’s Structure
In the newly created package folder, you’ll find a Sources
directory. This is where you’ll write the code for your library. You can also add a Tests
folder to create unit tests for your library, ensuring it works as expected.
Open Package.swift
and customize the package details. For example, specify platform requirements and dependencies if needed:
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "ESNetworking",
platforms: [
.iOS(.v18)
],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "ESNetworking",
targets: ["ESNetworking"]),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "ESNetworking"),
.testTarget(
name: "ESNetworkingTests",
dependencies: ["ESNetworking"]
),
]
)
In this example:
platforms
specifies the minimum OS versions. You can add this in case it's not already included in your Package fileproducts
defines what the package will provide (in this case, a library called "ESNetworking").targets
are modules within your package. You have one main target for your library and another for its tests.
Step 3: Write Your Library Code
In the Sources/ESNetworking
folder, add your Swift files. To keep this example small, we are going to add just a very simple class inside a NetworkingClient.swift file:
import Foundation
public class NetworkingClient {
public func get(url: String) async -> String {
return "Response"
}
}
Mark classes and functions you want to be publicly available with the public
access level, ensuring they’re accessible from other projects that import your package.
Step 4: Add Tests
To verify your code, add tests in the Tests/ESNetworkingTests
folder. Xcode creates a test file by default, but you can add more as needed. Here’s an example of a simple test:
import Testing
@testable import ESNetworking
@Test func example() async throws {
let sut = NetworkingClient()
let response = await sut.get(url: "https://fakeurl.com")
#expect(response == "Response")
}
Run the tests by selecting Product > Test in Xcode or using the ⌘U
shortcut.
Step 5: Publish Your Package on GitHub
To make your package publicly available, upload it to GitHub (or the platform you prefer):
- Initialize a Git repository in the package’s root folder (if you haven’t already):
git init
. - Add all files to the repository:
git add .
. - Commit the changes:
git commit -m "Initial commit"
. - Push the repository to GitHub. First, create a new repository on GitHub, then push your code:
git remote add origin https://github.com/username/ESNetworking.git
git push -u origin main
Step 6: Adding a Version Tag
Swift packages rely on version tags for versioning. To add a version tag, use the following command:
git tag 1.0.0
git push origin 1.0.0
This creates a versioned release that others can specify when adding your package to their projects. Check what version you should choose when publishing new changes to your libraries in our Software versioning article
Step 7: Using Your Package in a Project
Once your package is on GitHub with a version tag, anyone can use it by adding it as a dependency in their Xcode project:
- Go to File > Add Packages.
- Enter the URL for your GitHub repository and specify the version (such as 1.0.0).
- Xcode will add your package, making it available for import in the project.
You can now import and use your library in any project with import ESNetworking
.
Be the first to comment