The end of fat binaries: XCFrameworks
In 2019, Xcode 11 introduced a highly anticipated feature for every iOS developer: the ability to generate a framework that runs on both the simulator and the device.
Before this, it was already possible using lipo to generate a fat binary. Although feasible, Apple has long discouraged its use and has not offered a viable alternative until now.
Now we can use XCFramework, which generates a pseudo framework containing several frameworks for different platforms.
Let’s assume that your framework supports iOS devices, iOS simulators, and macOS. With XCFramework, we will have the three frameworks built-in, and when the project that uses the framework is built, Xcode will automatically select which of the contained frameworks to use.
Advantages of xcframework
- Support for multiple platforms in the same framework.
- Support for Swift, Objective-C, and C.
- Support for dynamic frameworks and static libraries.
- Support for Swift Package Manager.
- End of fat binaries.
Generating an XCFramework
In your project, create a new target (File -> New -> Target) in the “Cross Platform” section with the “Aggregate” type.
In the Build Phases of your target, add a Run Script section and paste the code below:
#Gerenare device framework
xcodebuild archive -scheme ${PROJECT_NAME} -archivePath "${PROJECT_DIR}/build/${PROJECT_NAME}-iphoneos.xcarchive" -sdk iphoneos SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES
#Generate simulator framework
xcodebuild archive -scheme ${PROJECT_NAME} -archivePath "${PROJECT_DIR}/build/${PROJECT_NAME}-iossimulator.xcarchive" -sdk iphonesimulator SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES
#Generate xcframework for both arches
xcodebuild -create-xcframework -framework "${PROJECT_DIR}/build/${PROJECT_NAME}-iphoneos.xcarchive/Products/Library/Frameworks/${PROJECT_NAME}.framework" -framework "${PROJECT_DIR}/build/${PROJECT_NAME}-iossimulator.xcarchive/Products/Library/Frameworks/${PROJECT_NAME}.framework" -output "${PROJECT_DIR}/build/${PROJECT_NAME}.xcframework"
#Open directory where xcframework were generate
open "${PROJECT_DIR}/build"
This code archives your project for both the device and the simulator, and then creates the XCFramework. The generated files will be in a folder called “build” in your project directory.
With the archive files, you will obtain the DSYMs of your compilations.
The golden tip
The xcodebuild command “ignores” the BUILD_LIBRARIES_FOR_DISTRIBUTION parameter (probably a bug that will be fixed in later versions). This behavior prevents Xcode from generating the swiftinterface file, which is needed for the create-xcframework command to work.
To solve this problem, the Build for Distribution flag should be set to YES in your project’s build settings as well.
To set this flag, open the Build Settings tab, select All in the exhibition level, and in the Build Options section, change the value of Build Libraries for Distribution to Yes.
Now, run your target again, and everything will work like a charm. You just need to drag the XCFramework file into your main app’s project and Xcode will take care of everything from there.