With the release of Xcode 12 Apple added a new way of distributing compiled iOS frameworks — that is, Swift Package Manager. In practice, SPM can distribute packaged frameworks, namely XCFrameworks.
For the scope of this article, we will build and distribute a fictitious framework named
1. Building the XCFramework
Before we can create the actual XCFramework we need to compile our source code for each platform / architecture variant we want to support. In this case, we're adding support for iOS and the simulator.
# iOS devices xcodebuild archive \ -scheme StarWarsKit \ -archivePath "archives/StarWarsKit-iOS.xcarchive" \ -destination "generic/platform=iOS" \ -sdk iphoneos \ SKIP_INSTALL=NO \ BUILD_LIBRARY_FOR_DISTRIBUTION=YES # iOS simulators xcodebuild archive \ -scheme StarWarsKit \ -archivePath "archives/StarWarsKit-iOS-simulator.xcarchive" \ -destination "generic/platform=iOS Simulator" \ -sdk iphonesimulator \ SKIP_INSTALL=NO \ BUILD_LIBRARY_FOR_DISTRIBUTION=YES
It's important to note the
BUILD_LIBRARY_FOR_DISTRIBUTION setting is enabled. This will instruct the compiler to generate the
.swiftmodule interface that will allow us to import the framework into our application.
Once the individual archives have been compiled, we can create the XCFramework itself.
xcodebuild -create-xcframework \ -framework "archives/StarWarsKit-iOS.xcarchive/Products/Library/Frameworks/StarWarsKit.framework" \ -framework "archives/StarWarsKit-iOS-simulator.xcarchive/Products/Library/Frameworks/StarWarsKit.framework" \ -output "StarWarsKit.xcframework"
At this point you should be able to see the
StarWarsKit.xcframework at the root of your project. For testing purposes you can already include it in an application as it's fully ready to be consumed.
2. Publicly host the XCFramework
In order to distribute the compiled package, we need to host it somewhere with public accessibility. One way to do this is to push the XCFramework to a git repository and use that as the binary target URL.
Alternatively, we can create a GitHub Release with our artifacts. The advantage of this approach is the fact we don't need to keep a large history of artifacts alongside our source code, therefore, not hindering the checkout process.
Going with this route, we need to create a ZIP file with the XCFramework at the root and calculate the checksum of the resulting file, which will be needed for the Package manifest.
# Create the ZIP file zip -r -X StarWarsKit.xcframework.zip StarWarsKit.xcframework # Calculate the checksum swift package compute-checksum StarWarsKit.xcframework.zip
After publishing a GitHub release with the changelog and the zip file artifact we can proceed with the creation of the Package manifest.
3. Creating the Package manifest
SPM allows us to publish source code in various formats - actual source code, locally stored binaries and URL-based binaries. In our approach, we've decided to go with the URL-based approach (a.k.a. GitHub Release), hence the need for the checksum.
At the root of the project, create the following
Package.swift. Be aware that you need to use the correct URL to your GitHub repo as well as the checksum calculated in the previous step.
// swift-tools-version:5.3 import PackageDescription let package = Package( name: "StarWarsKit", platforms: [ .iOS(.v10), ], products: [ .library( name: "StarWarsKit", targets: ["StarWarsKit"] ), ], dependencies: , targets: [ .binaryTarget( name: "StarWarsKit", url: "https://github.com/YOUR_ORG/star-wars-kit/releases/download/1.0.0-alpha.1/StarWarsKit.xcframework.zip", checksum: "b24b18fb3c11ca154242742ad9a18c3c67d4a75cb75b3e05d7dbb82cbd367227" ), ] )
4. Consuming the framework
In your application project, by going to File > Swift Packages > Add Package Dependency you can type the URL of your GitHub repository and select the appropriate version if you want to consume.
All there is left to do is build the project and use the framework. 🚀
All this manual and tedious process could be automated by leveraging GitHub Actions which provides developers with a generous amount of build minutes. Taking away the manual process of the equation, aside of saving precious time, we also improve the reliability of our workflow.
If you liked this article or have something to add, we are available, as always, via our Support Channel.