Skip to main content

Swift Package Distribution

Introduction

After creating a Swift package, the next logical step is to distribute it so others can use your code in their projects. Swift package distribution involves preparing your package for public consumption, versioning it properly, and making it available through various distribution channels. This guide will walk you through the process of distributing your Swift packages effectively.

Understanding Package Distribution

Swift packages can be distributed in several ways, with the most common being:

  1. Version Control Systems (like GitHub, GitLab, BitBucket)
  2. Private Package Repositories
  3. Swift Package Registry

Before distributing your package, it's important to understand how Swift Package Manager (SPM) handles package resolution and versioning.

Versioning Your Swift Package

Swift Package Manager relies heavily on semantic versioning (SemVer), which follows the format MAJOR.MINOR.PATCH:

  • MAJOR: Incompatible API changes
  • MINOR: Added functionality (backward-compatible)
  • PATCH: Bug fixes (backward-compatible)

Setting Up Versioning

Versioning in Swift packages is handled using Git tags. When you're ready to release a version:

bash
git tag 1.0.0
git push origin 1.0.0

This creates a tag that SPM can use as a version reference.

Version Rules in Package.swift

Your Package.swift file includes version requirements for dependencies:

swift
// Package.swift
let package = Package(
name: "MyPackage",
products: [
.library(name: "MyLibrary", targets: ["MyLibrary"]),
],
dependencies: [
// Examples of version requirements:
.package(url: "https://github.com/example/package1.git", from: "1.0.0"),
.package(url: "https://github.com/example/package2.git", .upToNextMajor(from: "2.0.0")),
.package(url: "https://github.com/example/package3.git", .exact("3.1.2")),
],
targets: [
.target(name: "MyLibrary", dependencies: ["package1", "package2", "package3"]),
]
)

Preparing Your Package for Distribution

1. Documentation

Good documentation is essential for package adoption. Consider including:

  • A comprehensive README.md file
  • API documentation using markup comments
  • Usage examples

Here's an example of a documentation comment for a Swift function:

swift
/// Processes an array of strings and returns consolidated results
///
/// This function takes multiple strings, processes them according to the specified options,
/// and returns a consolidated output.
///
/// - Parameters:
/// - inputs: An array of strings to process
/// - options: Options to control processing behavior
/// - Returns: A processed string result
/// - Throws: `ProcessingError` if the inputs cannot be processed
public func processStrings(_ inputs: [String], options: ProcessingOptions) throws -> String {
// Implementation
}

2. Testing

Ensure your package has comprehensive tests before distribution:

swift
import XCTest
@testable import MyLibrary

final class MyLibraryTests: XCTestCase {
func testBasicFunctionality() {
// Given
let inputValue = "test"

// When
let result = MyLibrary.process(inputValue)

// Then
XCTAssertEqual(result, "PROCESSED: test")
}

// More tests...
}

3. License

Add a license file to your package to clarify how others can use your code:

bash
touch LICENSE

Common open-source licenses include MIT, Apache 2.0, and GPL.

Publishing to GitHub

GitHub is the most common platform for distributing Swift packages:

  1. Create a repository on GitHub
  2. Push your local repository to GitHub:
bash
git remote add origin https://github.com/yourusername/your-package.git
git push -u origin main
  1. Create and push a tag for your first release:
bash
git tag 1.0.0
git push origin 1.0.0

Using Your Published Package

Once published, others can use your package by adding it to their Package.swift file:

swift
dependencies: [
.package(url: "https://github.com/yourusername/your-package.git", from: "1.0.0")
]

Or in Xcode:

  1. Select File > Swift Packages > Add Package Dependency
  2. Enter your repository URL
  3. Choose version requirements
  4. Select which targets should use the package

Real-World Example: Creating and Publishing a Utility Package

Let's walk through creating and publishing a simple string utility package:

1. Create the package

bash
mkdir StringUtils
cd StringUtils
swift package init --type library

2. Implement functionality

swift
// Sources/StringUtils/StringUtils.swift
public struct StringUtils {
public static func capitalize(_ string: String) -> String {
guard !string.isEmpty else { return string }
return string.prefix(1).uppercased() + string.dropFirst()
}

public static func reverse(_ string: String) -> String {
return String(string.reversed())
}

public static func isPalindrome(_ string: String) -> Bool {
let processed = string.lowercased().filter { $0.isLetter }
return processed == String(processed.reversed())
}

public init() {}
}

3. Write tests

swift
// Tests/StringUtilsTests/StringUtilsTests.swift
import XCTest
@testable import StringUtils

final class StringUtilsTests: XCTestCase {
func testCapitalize() {
XCTAssertEqual(StringUtils.capitalize("hello"), "Hello")
XCTAssertEqual(StringUtils.capitalize(""), "")
XCTAssertEqual(StringUtils.capitalize("a"), "A")
}

func testReverse() {
XCTAssertEqual(StringUtils.reverse("hello"), "olleh")
XCTAssertEqual(StringUtils.reverse(""), "")
}

func testIsPalindrome() {
XCTAssertTrue(StringUtils.isPalindrome("racecar"))
XCTAssertTrue(StringUtils.isPalindrome("A man, a plan, a canal: Panama"))
XCTAssertFalse(StringUtils.isPalindrome("hello"))
}
}

4. Create a README.md

markdown
# StringUtils

A Swift package providing useful string manipulation utilities.

## Installation

Add the following dependency to your Package.swift:

```swift
dependencies: [
.package(url: "https://github.com/yourusername/StringUtils.git", from: "1.0.0")
]

Usage

swift
import StringUtils

// Capitalize a string
let capitalized = StringUtils.capitalize("hello") // "Hello"

// Reverse a string
let reversed = StringUtils.reverse("hello") // "olleh"

// Check if a string is a palindrome
let isPalindrome = StringUtils.isPalindrome("racecar") // true

License

This package is released under the MIT license.


### 5. Publish to GitHub

```bash
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/yourusername/StringUtils.git
git push -u origin main
git tag 1.0.0
git push origin 1.0.0

Best Practices for Package Maintenance

  1. Keep a Changelog: Document changes between versions
  2. Semantic Versioning: Follow SemVer strictly to avoid breaking clients
  3. CI/CD Integration: Set up automated testing for every commit
  4. Swift Version Compatibility: Specify Swift version requirements
  5. Platform Support: Be clear about which platforms your package supports

Example Package.swift with Platform Requirements

swift
// swift-tools-version:5.5
import PackageDescription

let package = Package(
name: "MyPackage",
platforms: [
.iOS(.v13),
.macOS(.v11),
.watchOS(.v6),
.tvOS(.v13)
],
products: [
.library(name: "MyLibrary", targets: ["MyLibrary"]),
],
dependencies: [
// Dependencies go here
],
targets: [
.target(name: "MyLibrary", dependencies: []),
.testTarget(name: "MyLibraryTests", dependencies: ["MyLibrary"]),
]
)

Private Package Hosting

For proprietary code, you can use:

  1. Private GitHub/GitLab repositories: Requires authentication
  2. Self-hosted Git servers: For complete control
  3. Swift Package Collections: For organizing and sharing packages within teams

Summary

Swift package distribution is an essential skill for sharing your code with the Swift community or within your organization. By following semantic versioning, providing good documentation, writing comprehensive tests, and using the appropriate platforms for distribution, you can make your Swift packages accessible and useful to other developers.

Remember these key points:

  • Use Git tags for versioning
  • Write clear documentation
  • Include tests for your package
  • Choose an appropriate license
  • Specify platform and Swift version requirements
  • Maintain your package with semantic versioning principles

Additional Resources

Exercises

  1. Create a simple utility package and publish it to GitHub
  2. Add versioning to an existing Swift package
  3. Practice writing documentation comments for your package's public API
  4. Create a Swift Package Collection to group related packages
  5. Set up GitHub Actions to automatically run tests when changes are pushed to your package repository


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)