How to Make a Universal Framework in iOS | XCFramework | Swift

Learn how you can make a framework that can run on both simulator and devices

Before XCFramework, it was officially impossible to build a framework that would contain code aiming on both real iOS devices and the Simulator. But with apple announcement of XCFramework in WWDC 2019, we can now make a single framework that can bundle up any framework with flavours for any platform or device that Xcode supports. Everything in one single place, with one single item to distribute only.

We will go through few steps to make a XCFramework.

Create New Framework from Xcode

Open your Xcode, click New, click Project and choose ‘Framework’ under iOS tab. Give it a suitable name. In my case, its ‘UniversalFramework’.

Choosing Framework option

Write all your code inside framework

Create a new file in your framework project under ‘UniversalFramework’ folder, and inside the file, implement the working of your framework. You can create as many files as you can to achieve your functionality. In my case, I am simply creating a new file name LogFile.swift and inside that file, I am writing a function that will print some text.

LogFile.swift

Change ‘Build Libraries for Distribution’ to Yes

Once you are done with the code, navigate to ‘Build Settings’ under ‘TARGETS’ and look for ‘Build Options’. Inside there, change ‘Build Libraries for Distribution’ from No to Yes. This produces a module interface file which shows your public API when someone jumps to definition of your module in Xcode.

Navigate to your framework via Terminal

Now close your framework project and open up terminal. You are going to work on terminal til the end. Inside terminal, navigate to the path where your framework is located. In my case its inside a folder, which is located on Desktop. I simply dragged and dropped my framework file, inside which my ‘UniversalFramework.xcodeproj’ is located, to terminal, and I was automatically navigated to that path.

Archiving Framwork

We will now archive our framework for the simulator and iOS.

First we will start with Simulator. Enter following command inside your terminal: (You can copy the whole command, paste it inside textEdit, replace ‘UniversalFramework’ with your framework name, and paste it inside terminal )

xcodebuild archive \
-scheme UniversalFramework \
-configuration Release \
-destination 'generic/platform=iOS Simulator' \
-archivePath './build/UniversalFramework.framework-iphonesimulator.xcarchive' \
SKIP_INSTALL=NO \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES

After simulator successful archive,we will move on to iOS. Enter the following command inside your terminal :

xcodebuild archive \
-scheme UniversalFramework \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath './build/UniversalFramework.framework-iphoneos.xcarchive' \
SKIP_INSTALL=NO \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES

To check if you have successfully archived for both simulator and iOS, go to your framework project via Finder, and you’ll see a folder name ‘build’. Inside that folder, you’ll find two xcarchive files, both for simulator and iOS. Now we have to merge both of these into one single xcframwork. For that, enter the following command inside your terminal :

xcodebuild -create-xcframework \
-framework './build/UniversalFramework.framework-iphonesimulator.xcarchive/Products/Library/Frameworks/UniversalFramework.framework' \
-framework './build/UniversalFramework.framework-iphoneos.xcarchive/Products/Library/Frameworks/UniversalFramework.framework' \
-output './build/UniversalFramework.xcframework'

You will get a success message indicating that your xcframework has been written successfully. Go to build folder again, and there it is, an xcframework folder. That’s it.

Testing our Framework

Just create a new project, click on your project name under ‘TARGETS’ and drag and drop UniversalFramework.xcframework folder inside ‘Frameworks, Libraries, and Embedded Content’ which is inside ‘General’ tab.

Drag and Drop Universal Framework

Now you can use this framework on both iOS and Simulator. Import UniversalFramework inside your new project’s file and inside viewDidLoad(), write printLog(). Build and run on both simulator and iOS device, and you will get the same result. One last thing, when we were building our framework, we changed ‘Build Libraries for Distribution’ from No to Yes. You might be wondering why we did that? Well, right click on printLog() function inside your new project, and go to ‘Jump to Definition’, and you will see that Xcode has created a file inside which our public API’s are showing. This is same as when we go to definition for any swift framework’s function.

Feel free to comment, if you have any queries!

Happy Coding!

iOS Developer — Connect with me www.linkedin.com/in/Muhammad-Abubakar-iOS