Building an iOS SDK has traditionally meant generating multiple builds for different architectures, which complicates binary distribution.
In this tutorial we'll walk through, step by step, how to create an XCFramework , packaging every architecture into a single bundle and getting rid of heavy "Fat Binaries" and separate builds.
Unlike CocoaPods or SPM —which distribute dependencies by exposing the source code— XCFramework distributes already-compiled code. It's the ideal option for commercial SDKs, internal libraries, or any scenario where you need to ship functionality without revealing the implementation, guaranteeing universal compatibility regardless of the client's integration method.
Prerequisites:
Xcode 15 or higher, basic Swift knowledge, and access to a terminal with permission to run xcodebuild.
Create the SDK project
- Open Xcode and select "Create New Project..."
- Select the "iOS" platform
- In the
"Framework & Library"
section, select the
"Framework"
template
- Enter the name you want to give your SDK
- Enter the organization identifier , using " reverse domain name notation "
- Select
Swift
as the language for the SDK
Implementing the SDK
Once the project is created, it's time to implement your SDK's logic and define the public API that consuming apps will use.
During compilation, every element (classes, protocols, enums, structs, functions, etc.) marked as public will be exposed for external use. Anything else stays as an internal SDK component.
public class Foo {
// Allows this class to be instantiated from outside the SDK
public init() {}
public func bar() -> Bool {
return true
}
}
Building the XCFramework for distribution
Now let's build the XCFramework using xcodebuild for different architectures. We'll use three commands: two to compile the SDK for each architecture, and one to package everything into an XCFramework.
In the commands below, mysdk is a placeholder — replace it with the actual name of your project (the same one you used when creating it in Xcode).
Build the SDK for iPhone and Simulator
iOS Device
xcodebuild archive \
-project "mysdk.xcodeproj" \
-scheme "mysdk" \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath "build/iphone.xcarchive" \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
This command produces the framework optimized for physical iPhone/iPad devices.
iOS Simulator
xcodebuild archive \
-project "mysdk.xcodeproj" \
-scheme "mysdk" \
-configuration Release \
-destination 'generic/platform=iOS Simulator' \
-archivePath "build/simulator.xcarchive" \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES
This command builds the simulator version (x86_64 and ARM64 for Apple Silicon Macs).
The BUILD_LIBRARY_FOR_DISTRIBUTION=YES flag enables
module stability
, keeping the XCFramework compatible with future Swift compiler versions. It is mandatory when distributing an SDK as a binary.If you want to skip signing the compiled binaries, add the following arguments to both commands:CODE_SIGNING_REQUIRED=NOCODE_SIGNING_ALLOWED=NOCODE_SIGN_IDENTITY=''
Create the XCFramework
xcodebuild -create-xcframework \
-framework "build/iphone.xcarchive/Products/Library/Frameworks/mysdk.framework" \
-framework "build/simulator.xcarchive/Products/Library/Frameworks/mysdk.framework" \
-output "build/mysdk.xcframework"
This produces a folder containing the XCFramework at "build/mysdk.xcframework" , ready to distribute.
Consuming the XCFramework from an app
Once the .xcframework is generated, any iOS project can integrate it by following these steps:
- Drag
mysdk.xcframeworkinto the Xcode project navigator. - In the target's "General" tab, under "Frameworks, Libraries, and Embedded Content" , make sure it's set to "Embed & Sign" .
- You can now import it from any Swift file in your app:¬
import mysdk
let foo = Foo()
print(foo.bar())
Distributing the XCFramework
You have several options to deliver the binary to your clients or teams:
-
GitHub Releases
: zip the
mysdk.xcframeworkfolder and attach it to a versioned release. It's the simplest option for open-source or internal SDKs where consumers have repo access. - Swift Package Manager with `binaryTarget` : expose the XCFramework as a remote SPM package. Consumers add it via a URL and a version, getting explicit control over updates.
- Private registry or CDN : for commercial SDKs, publish the ZIP on your own authenticated server and sign its checksum to guarantee integrity.
Wrapping up
With the XCFramework built, you can now distribute your SDK to any iOS app that wants to integrate it. You get a professional package that works universally across devices and simulators, with no extra configuration required from the developers consuming it.