Swift + Xcode Library: Build, Document & Share (Step-by-Step)
Swift + Xcode Library: Build, Document & Share (Step-by-Step)
What you’ll build
- A Swift package (the standard way to make libraries).
- It works in Xcode (iOS, macOS, tvOS, watchOS).
- It has tests, documentation, CI (optional), and versioned releases.
- You’ll share it via Swift Package Manager (SPM). (Optional: CocoaPods + XCFramework.)
Prerequisites
- Xcode 14 or later (Xcode includes Swift and supports Swift Packages).
- A GitHub account (or any Git server).
- Basic terminal use.
Tip: “SPM” = Swift Package Manager. It’s built into Swift/Xcode and is the easiest way to share code.
1) Create the library (Swift Package)
# 1) Make a new folder and enter it
mkdir GreeterKit && cd GreeterKit
# 2) Create a Swift package (library template)
swift package init --type library
This creates a structure like:
GreeterKit/
├── Package.swift
├── README.md
├── Sources/
│ └── GreeterKit/
│ └── GreeterKit.swift
└── Tests/
└── GreeterKitTests/
└── GreeterKitTests.swift
Open it in Xcode:
open Package.swift
Xcode will show your package like a project.
2) Add simple code
Replace Sources/GreeterKit/GreeterKit.swift with:
public struct Greeter {
public init() {}
/// Returns a friendly greeting.
/// - Parameter name: The name to greet.
/// - Returns: Example: "Hello, Luna!"
public func hello(name: String) -> String {
"Hello, \(name)!"
}
}
Note: The keyword
publiclets apps outside your package use the type/function.
3) Add tests (to prove it works)
Edit Tests/GreeterKitTests/GreeterKitTests.swift:
import XCTest
@testable import GreeterKit
final class GreeterKitTests: XCTestCase {
func testHello() {
let g = Greeter()
XCTAssertEqual(g.hello(name: "World"), "Hello, World!")
}
}
Run tests:
swift test
Or in Xcode: Product ▸ Test.
4) Set platform support (optional but recommended)
Edit Package.swift to declare platforms:
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "GreeterKit",
platforms: [
.iOS(.v13), .macOS(.v12), .tvOS(.v13), .watchOS(.v7)
],
products: [
.library(name: "GreeterKit", targets: ["GreeterKit"])
],
targets: [
.target(name: "GreeterKit"),
.testTarget(name: "GreeterKitTests", dependencies: ["GreeterKit"])
]
)
“Platforms” tell users the minimum OS versions your library supports.
5) Use the library in an Xcode app (local)
If you want to try it in a sample app without pushing to GitHub:
- In your app project: File ▸ Add Packages…
- Click Add Local… and choose your
GreeterKitfolder. - Add the product GreeterKit to your app target.
Then:
import GreeterKit
let result = Greeter().hello(name: "Nana")
print(result) // Hello, Nana!
6) Make nice documentation (DocC)
DocC turns your /// comments into clean docs.
Quick start (Xcode UI)
- In Xcode: Product ▸ Build Documentation.
- You’ll see API docs generated from comments.
- Add more
///comments to improve it. - Optional: File ▸ New ▸ File… ▸ Documentation Catalog to create a
.doccbundle for guides and tutorials.
Static website (optional, GitHub Pages)
Add Apple’s DocC plugin so the
swiftcommand can export static docs:In
Package.swiftadd:dependencies: [ .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0") ],
Export docs:
swift package generate-documentation \ --target GreeterKit \ --disable-indexing \ --transform-for-static-hosting \ --hosting-base-path GreeterKit \ --output ./docs
Commit
/docsand turn on GitHub Pages for thedocs/folder.
7) Add CI (GitHub Actions) to build & test (optional)
Create .github/workflows/ci.yml:
name: CI
on:
push: { branches: [ main ] }
pull_request: { branches: [ main ] }
jobs:
linux-swiftpm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: swift-actions/setup-swift@v2
with:
swift-version: "5.9"
- name: Build
run: swift build -v
- name: Test
run: swift test -v
This makes sure the package builds and tests pass on every push/PR.
8) Choose a license
Create LICENSE with a friendly license like MIT:
MIT License
Copyright (c) 2025 ...
Permission is hereby granted, free of charge, to any person obtaining a copy...
A license tells others how they can use your code.
9) Prepare for release
Initialize Git and make the first commit:
git init git add . git commit -m "Initial library"
Create a remote repo (e.g., GitHub) and push:
git branch -M main git remote add origin https://github.com/<you>/GreeterKit.git git push -u origin main
Tag a version (use Semantic Versioning: MAJOR.MINOR.PATCH):
git tag 1.0.0 git push origin 1.0.0
SPM uses Git tags. When others add your package, they pick a version rule like
from: "1.0.0".
10) Share via Swift Package Manager (recommended)
How others add your library (Xcode)
- File ▸ Add Packages…
- Paste your repo URL, e.g.
https://github.com/<you>/GreeterKit - Choose Dependency Rule: Up to Next Major starting at 1.0.0
- Add the product GreeterKit to their target.
How others add it in their own Package.swift
// In their package:
dependencies: [
.package(url: "https://github.com/<you>/GreeterKit.git", from: "1.0.0")
],
targets: [
.target(
name: "SomeApp",
dependencies: [
.product(name: "GreeterKit", package: "GreeterKit")
]
)
]
11) Optional: Share as an XCFramework (binary)
Use this when you want to ship a prebuilt binary (for faster builds or closed-source).
Add a framework target in an Xcode project (or use
xcodebuildwith your package-generated project).Build archives for each platform and simulator:
xcodebuild archive \ -scheme GreeterKit \ -destination "generic/platform=iOS" \ -archivePath build/ios \ SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES xcodebuild archive \ -scheme GreeterKit \ -destination "generic/platform=iOS Simulator" \ -archivePath build/iossim \ SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES
Create the XCFramework:
xcodebuild -create-xcframework \ -framework build/ios.xcarchive/Products/Library/Frameworks/GreeterKit.framework \ -framework build/iossim.xcarchive/Products/Library/Frameworks/GreeterKit.framework \ -output GreeterKit.xcframework
Distribute
GreeterKit.xcframework(attach to GitHub Release). Users drag it into their app and set Embed & Sign.
BUILD_LIBRARY_FOR_DISTRIBUTION=YEShelps with Swift “module stability” so your binary is usable across Swift minor versions.
12) Optional: CocoaPods support
Create
GreeterKit.podspec:Pod::Spec.new do |s| s.name = 'GreeterKit' s.version = '1.0.0' s.summary = 'Friendly greeting utilities.' s.description = 'A tiny Swift library that says hello.' s.homepage = 'https://github.com/<you>/GreeterKit' s.license = { :type => 'MIT' } s.author = { '<you>' => '<you>@email.com' } s.source = { :git => 'https://github.com/<you>/GreeterKit.git', :tag => s.version.to_s } s.swift_version = '5.9' s.platform = :ios, '13.0' s.source_files = 'Sources/GreeterKit/**/*.swift' end
Validate:
pod lib lint
Publish:
pod trunk push GreeterKit.podspec
Users can then add
pod 'GreeterKit', '~> 1.0'to their Podfile.
13) Great README template (copy-paste)
Create README.md:
# GreeterKit A tiny Swift library that says hello. ## Installation (Swift Package Manager) - Xcode: File ▸ Add Packages… URL: `https://github.com/<you>/GreeterKit` - Version: Up to Next Major from 1.0.0 ## Usage ```swift import GreeterKit print(Greeter().hello(name: "World"))
Requirements
- iOS 13+ / macOS 12+ / tvOS 13+ / watchOS 7+
Documentation
- See the API docs (DocC): https://<you>.github.io/GreeterKit/
License
MIT
14) Release checklist
- ☐ All public APIs have clear
///comments.
- ☐
swift testpasses.
- ☐
README.mdshows install + usage.
- ☐
LICENSEpresent.
- ☐ Tag created:
git tag 1.0.0 && git push origin 1.0.0.
- ☐ (Optional) GitHub Release notes.
- ☐ (Optional) Docs exported to
docs/and GitHub Pages enabled.
- ☐ (Optional) XCFramework built and attached to release.
- ☐ (Optional) CocoaPods podspec pushed.
15) Troubleshooting (common issues)
“No such module ‘GreeterKit’”
- Make sure you added the product to your app target (Xcode target settings).
- Clean build folder (Shift+Cmd+K) and rebuild.
“Module compiled with Swift X.Y cannot be imported by Swift X.Z”
- Rebuild with your current Xcode/Swift.
- If distributing a binary, use BUILD_LIBRARY_FOR_DISTRIBUTION=YES.
SPM can’t find the version
- Did you push the Git tag? (git push origin 1.0.0)
- The repo must be public (or accessible to the user).
16) Next steps (ideas)
- Add more tests (edge cases).
- Add async APIs if useful.
- Add a
.doccguide with examples and screenshots.
- Set up another CI job on
macos-latestto build for iOS withxcodebuild.
- Add a simple example app in
Examples/HelloApp/.