A noob’s guide to creating a ‘Fat Library’ for iOS

Recently I faced a situation in which I had to use a third party library in my project but that library was not available on Cocoa Pods.

Swifter is a very nice Twitter framework written in Swift. It has a great numbers of stars(likes) and forks. But unfortunately this framework is not available on Cocoa Pods (at least till 22/12/2017).

The only method to import that project is to drag the whole Xcode project into your own project. Since this project has separate frameworks for Mac, iOS and demo apps for iOS and Mac too, this makes it a cumbersome project to be added within your own project.

After using Cocoa Pods for library management for a very long time, I didn’t want to embed a whole project within my own project. It didn’t seem right. So I embarked on the journey of finding out alternate ways.

Importing a static framework (the wrong way)

The easiest solution is to embed the iOS framework produced by the library in your project. It can be done in 4 steps.

  1. Select your framework and platform.

2. Build and extract the framework from products folder.

3. Embed the extracted framework in ‘Embedded Binaries’

4. Now import the module and use it.

Problem with importing a static framework

The above technique works. But the problem here is that we created the framework targeting simulator platform. So the binary generated was of simulator specific architecture only (x86).

If you try to build your project for device, it will fail. The reason here is that device specific architecture is missing from the framework that we added in the last step.

You can repeat above steps and create a framework for device instead of simulator but then, it won’t work for simulator.

So in order to solve this problem permanently we need to find a way to embed both the architectures (x86 and arm) in a single framework. The solution is a fat library.

Fat Library

A fat library is simply a library with multiple architectures. In our case it will contain x86 and arm architectures. The proper name is ‘Universal Static Library’. But we will stick with ‘fat library’ since its smaller to write and that is exactly what our resultant library would be. Fat!!! with multiple architectures in it.

Creating a Fat Library

There are many articles available on the internet for creating a fat library. All of them are very technical, hard to follow along and have a high chance of failure.

I have found a new and very easy way of creating a fat library. This doesn’t involve any complex script. The steps are simple and easy to follow.

We will use Swifter project to create a fat library.

  1. Download the project from here and open it in Xcode.
  2. Build ‘SwifteriOS’ target for iOS simulator and extract framework from products folder on your desktop.
  3. Rename the framework to SwifteriOS-sim.framework so that it is distinguishable later.
  4. Repeat the steps 2 and 3 for iOS device. You can select ‘Generic iOS Device’. Don’t forget to rename the framework to Swifter-dev.framework.
  5. Use the following command to combine both binaries into a single fat binary file (Make sure you are on desktop while running this command).
$lipo -create ./SwifteriOS-sim.framework/SwifteriOS ./SwifteriOS-dev.framework/SwifteriOS -output ./SwifteriOS

7. Copy SwifteriOS binary file created in above step and replace it with the binary in SwifteriOS-dev.framework folder.

8. Open ‘Info.plist’ file contained in the same folder.

9. Add ‘iPhoneSimulator’ string in ‘CFBundleSupportedPlatforms’ array.

10. The final plist file would look like this:

\

11. From folder

SwifteriOS-sim.framework/Modules/SwifteriOS.swiftmodule/

copy ‘x86_64.swiftdoc’ and ‘x86_64.swiftmodule’ and paste them to

SwifteriOS-dev.framework/Modules/SwifteriOS.swiftmodule/

12. By following above steps you have converted SwifteriOS-dev.framework from device only to a universal fat framework. Rename it to SwifteriOS.framework.

13. Include this framework via ‘Embeded Binaries’ option in Xcode. Import the module in your file and you would be able to compile it successfully.

I have tested this technique in Xcode 10 and 11 with both Swift and Objective-C languages.

If you liked this post then don’t forget to clap :)