Menu Home

The end of fat binaries: XCFrameworks

#blindPeople: the image shows the XCFramework logo with the its name written right bellow.

In 2019, Xcode 11 came with a new feature that every iOS developer has always wanted: to generate a framework that runs on both the simulator and the device.

Before that, this was already possible, using lipo to generate a fat binary. Although possible, Apple has long discouraged its use, but has never offered a viable alternative to it.

Now we can use xcframework, which generates a pseudo framework, which contains several frameworks for different platforms.

Let’s assume that your framework supports iOS devices, iOS simulator and macOS. With xcframework, we will have the 3 frameworks built-in, and when the project that will use the framework is built, Xcode will automatically select which of the contained frameworks it should 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.

Gerando um XCFramework

In your project, create a new target (File -> New -> Target) in “Cross Platform” section with “Aggregate” type.

#blindPeople: the image shows the Xcode’s New Target window, with Aggregate option selected.

At Build Phases of your target, add a Run Script section and paste the code bellow:

#blindPeople: the image shows the Build Phases tab of our created Aggregate target, with the code pasted in a Run Script step.
#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 basically archives your project for both device and simulator, and then creates the xcframework. The generated files will be at a folder called “build” in your project directory.

With archive files, you will obtain the DSYMS of your compilations.

The golden tip

The xcodebuild command “ignores” the BUILD_LIBRARIES_FOR_DISTRIBUTION parâmetro (probably a bug that will be fixed in later versions). That behaviour makes Xcode to NOT generate the swiftinterface file, which is needed to create-xcframework to work.

To solve this problem, the Build for Distribution flag should be set to YES in your project’s build settings too.

To set this flag, open Build Settings tab, select All in exhibition level, and at Build Options section, change the value of Build libraries for distribution to Yes.

#blindPeople: the image shows the Build Settings tab of our Framework, with Build Libraries for Distribution value set as 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 be in charge of everything by now.

Categories: Tutorials

Tagged as:

André Salla