Building an iOS SDK using XCFramework

June 15, 2025

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
    Selecting the "Framework" template in Xcode when creating a new project
  • 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
    Setting the SDK's name, organization identifier, and Swift language in Xcode

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=NO
CODE_SIGNING_ALLOWED=NO
CODE_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:

  1. Drag mysdk.xcframework into the Xcode project navigator.
  2. In the target's "General" tab, under "Frameworks, Libraries, and Embedded Content" , make sure it's set to "Embed & Sign" .
  3. 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.xcframework folder 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.