XCFramework is an Apple binary format that combines libraries for iOS, macOS, tvOS, and watchOS in a single package. It was designed to replace .framework and eliminate the problems of fat binaries when building for different simulator and device architectures. According to Apple WWDC 2019, XCFramework became the mandatory format for distributing SDKs that support multiple platforms, and completely replaced the outdated approach with universal binaries.
Key Takeaways
XCFramework is a packaging format for binary libraries and frameworks introduced by Apple at WWDC 2019. Its main goal is to create a single bundle that contains compiled versions of a library for all target platforms and architectures.
Before XCFramework, developers used .framework with fat binaries combining multiple architectures via the lipo utility. This approach caused problems: when building a project for the simulator, the fat binary contained both simulator and device architectures, leading to errors when submitting the build to the App Store. Developers had to write Run Script phases to remove unnecessary architectures.
According to Apple Developer Documentation (2024), XCFramework supports all platforms in the Apple ecosystem: iOS, iPadOS, macOS, tvOS, watchOS, visionOS, and Mac Catalyst applications. Each platform gets a separate slice inside the package, eliminating architecture conflicts and simplifying SDK distribution.
XCFramework is used in three main scenarios: distributing closed-source SDKs to third-party developers, distributing native modules for Flutter and React Native, and publishing libraries that require pre-compilation. The format is mandatory for all new SDKs published in the Apple ecosystem.
Developers choose XCFramework when source code cannot be disclosed, when the library uses proprietary algorithms, or when license protection is required. Unlike Swift Package Manager, which works with source code, XCFramework delivers already compiled binary files.
The fat binary problem was that a universal binary contained multiple architectures in a single Mach-O file. When building an app for the simulator, Xcode included both the device arm64 architecture and the simulator x86_64 architecture — the App Store only accepted the device architecture.
The traditional solution involved adding a Run Script phase calling lipo to remove simulator architectures from the final build. This approach was fragile and broke with Xcode updates or when new architectures appeared (e.g., arm64 for the simulator on Apple Silicon).
According to Swift.org (2023), the Swift Package Manager team initially encountered this problem when trying to support binary dependencies. XCFramework solved it at the format level: each slice is a separate folder with an Info.plist describing the target platform and architecture. Xcode automatically selects the required slice at build time, requiring no post-processing.
Each slice in XCFramework contains only one platform-architecture combination. For example, ios-arm64 contains the binary only for iOS devices, and ios-x86_64-simulator only for the Intel Mac simulator. Xcode automatically selects the correct slice, eliminating the need for architecture removal scripts and reducing the risk of build errors.
The ios-arm64-x86_64-simulator slice was introduced to support Apple Silicon Macs. Previously, the simulator required a separate binary for arm64 (Apple Silicon) and x86_64 (Intel). XCFramework allows a fat binary inside a single simulator slice — this is the only exception where fat binary is justified.
An XCFramework package is a directory with the .xcframework extension, containing an Info.plist at the top level and folders with binary slices. Each slice includes a .framework or .a library for a specific platform.
MyLibrary.xcframework/
Info.plist
ios-arm64/
MyLibrary.framework/
Info.plist
MyLibrary
ios-x86_64-simulator/
MyLibrary.framework/
Info.plist
MyLibrary
macos-arm64-x86_64/
MyLibrary.framework/
Info.plist
MyLibrary
The package Info.plist contains the AvailableLibraries key, listing LibraryIdentifier, LibraryPath, and SupportedPlatform for each slice. Xcode reads this file when adding an XCFramework to a project and automatically configures search paths and the Embed Frameworks phase.
Each slice is a full .framework or static library with its own Info.plist. This allows XCFramework to support mixed types: static libraries for some platforms and dynamic frameworks for others, although in practice one type is used for all slices.
Creating an XCFramework is done via xcodebuild -create-xcframework. The command takes already built .framework or .a libraries for each platform and combines them into a single package.
The process consists of two steps: first, binaries are built for each target platform, then they are packaged into an XCFramework. Standard Xcode destination flags are used for building.
# Step 1: build frameworks for each platform
xcodebuild archive -scheme MyLibrary -destination "generic/platform=iOS Simulator"
xcodebuild archive -scheme MyLibrary -destination "generic/platform=iOS"
xcodebuild archive -scheme MyLibrary -destination "generic/platform=macOS"
# Step 2: create XCFramework
xcodebuild -create-xcframework -framework ./iOS/MyLibrary.framework -framework ./iOSSim/MyLibrary.framework -framework ./macOS/MyLibrary.framework -output ./MyLibrary.xcframework
The -create-xcframework flag was introduced in Xcode 11. The command automatically creates the correct directory structure and generates Info.plist with descriptions of all platforms. If one of the .framework files is damaged or built with the wrong architecture, xcodebuild reports an error at the validation stage.
For CI/CD, a shell script is used to automate building for all platforms and creating the XCFramework. A popular approach is a wrapper in the form of a Makefile or Fastlane lane with parameterized scheme and output path.
# build_xcframework.sh - automation script
set -e
SCHEME="MyLibrary"
OUTPUT="./build"
xcodebuild archive -scheme "$SCHEME" -sdk iphonesimulator -archivePath "$OUTPUT/sim.xcarchive"
xcodebuild archive -scheme "$SCHEME" -sdk iphoneos -archivePath "$OUTPUT/dev.xcarchive"
xcodebuild -create-xcframework -framework "$OUTPUT/dev.xcarchive/Products/Library/Frameworks/MyLibrary.framework" -framework "$OUTPUT/sim.xcarchive/Products/Library/Frameworks/MyLibrary.framework" -output "$OUTPUT/MyLibrary.xcframework"
Such a script runs in a CI pipeline (GitHub Actions, Bitrise, Jenkins) after tests pass. The resulting XCFramework is archived and uploaded as a release artifact or published through a dependency manager like CocoaPods using pod spec.
Integrating an XCFramework into an Xcode project does not require manual configuration of search paths. Simply drag the .xcframework into the Frameworks, Libraries, and Embedded Content section in the General settings of the target.
Unlike .framework, XCFramework does not require adding a Run Script phase to remove simulator architectures. Xcode automatically determines available slices and includes only the ones needed for the current build scheme. For a physical device, the ios-arm64 slice is used; for the simulator, ios-arm64-x86_64-simulator or ios-x86_64-simulator.
import MyLibrary
func processData() {
// XCFramework resolves the correct slice at build time
let processor = DataProcessor()
let result = processor.analyze(input: "sample")
print(result)
}
For CocoaPods, integration is done through a podspec with vendored_frameworks and a list of supported platforms. The dependency manager automatically determines which slices are needed for the project. Many commercial SDKs — Firebase, Adjust, AppsFlyer — have switched to XCFramework to simplify installation.
Swift Package Manager and XCFramework are not competitors but complement each other. SPM works with source code and builds dependencies on each project build. XCFramework provides ready-made binaries without requiring compilation on the consumer side.
With the release of Swift Package Manager 5.3, Apple added support for binary dependencies — SPM can now download an XCFramework as a remote dependency. Package.swift specifies the URL of the binary artifact and its checksum for verification.
According to Swift Package Manager documentation (2024), binary dependencies are recommended for SDKs that do not disclose source code, or for libraries whose build time is disproportionately long. For open-source projects, source code distribution via SPM is preferred.
| Criterion | XCFramework | Swift Package Manager |
|---|---|---|
| Format | Binary (.xcframework) | Source code |
| Code protection | Full | None |
| Build time | Minimal (copying) | Depends on code volume |
| Platform flexibility | All Apple platforms | Depends on Package.swift |
| Integration | Drag-and-drop or SPM | Package.swift |
Frequently Asked Questions
.framework is a legacy format containing a fat binary with device and simulator architectures. XCFramework stores each slice separately, eliminating architecture conflicts during builds. Apple recommends XCFramework for all new projects and for migrating existing ones.
CocoaPods has supported XCFramework since version 1.9. In podspec, simply specify spec.vendored_frameworks and spec.static_framework. The manager automatically resolves dependencies, taking into account available slices for the project platform.
Apple does not remove support for .framework, but recommends XCFramework exclusively for new SDKs. When submitting an app to the App Store with a fat binary in the old format, Invalid Bundle errors may occur due to simulator architectures, making XCFramework a practical necessity.
Starting with Swift 5.3, binary dependencies in SPM use XCFramework. Package.swift specifies the url and checksum of the binary package. SPM downloads, verifies integrity, and connects the XCFramework as a system dependency without compiling source code.
visionOS is supported in XCFramework starting with Xcode 15. At WWDC 2023, Apple confirmed that the format has been extended for Apple Vision Pro. The slice for visionOS has SupportedPlatform = xros and includes the arm64 architecture.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.