Create a Universal (Fat) Swift Framework

As a mobile developer at Wireless Registry, I am always tweaking, upgrading and personalizing our iOS and Android SDKs for developers to integrate into their apps. Of course, before anyone launches an app into production with our SDK on board, they need to test it across an array of devices and OS versions.

And while rejecting binaries with redundant architectural slices has been an unpopular quirk of the App Store review process for years, the vast majority of iOS developers rely upon simulators, at least in part, for expedient version and device testing. Thus, I normally provide developers with release-ready frameworks which include support exclusively for real device architectures (ARMv7, ARMv7s, ARM64), as well as frameworks with “fat” binaries, for testing on the simulator in addition to actual devices. In this post, I am going to describe perhaps the fastest way to turn a Swift framework into a fat binary (although, if you’ve got a few extra minutes, you should set up a runtime script in Build Phases instead of using the command line like me).

First things first: create your Swift framework

Create a new framework project in XCode, select “Framework & Library”, highlight the “Cocoa Touch Framework” icon, and name your project.

Add all your Swift files to the project and make sure any classes/methods meant to be accessed externally are declared public.

Finally, make sure you have set “Build Active Architecture Only” to NO for the debug version:

Now, make the framework universal

Open up your command line, navigate to a directory where you can hold a temporary file, and enter (but don’t execute):

$ lipo -create -output YOUR-FRAMEWORK-PROJECT-NAME

Now, go back to your framework project and run it two times: once targeting a real device that you have connected to your computer, and once targeting a simulator. Then, under the “Products” folder, right click YOUR-FRAMEWORK-PROJECT-NAME.framework, and select “Show in Finder”.

You should see a directory structure that looks something like this:

Right click on the executable file inside the Debug-iphoneos framework directory, hold down the option key, copy its path, and then paste it into the command line. Add a space, then do the same with the executable file inside the Debug-iphonesimulator framework directory.

Your command line should now look like this:

$ lipo -create -output YOUR-FRAMEWORK-PROJECT-NAME REAL-DEVICE-EXECUTABLE-PATH-NAME SIMULATOR-EXECUTABLE-PATHNAME

Now execute it! The result should be a new executable file in your designated directory. Delete the executable inside your Debug-iphoneos framework directory, and replace it with the one you just created.

Finally, drag the i386 and x86_64 slices from your Debug-iphonesimulator build into the .swiftmodule folder from the Debug-iphoneos directory. Your framework directory inside Debug-iphoneos is now universal!

Finally, import the framework into a Swift project

To see for yourself, start a new Swift project, navigate to the “general” tab inside the project window, and drag your .framework directory into Embedded Binaries (select “Copy Items if Needed”).

Now, simply import the framework, call its methods and classes anywhere in your code, and run it on a real device or a simulator!