
If you want to share code between multiple apps for the iOS and Mac platforms or just to bundle common functionalities into an easy-to-use package, this post will show you how to create an universal framework that can be linked into any Xcode project. It makes use of kstenerud’s awesome iOS Universal Framework. My DevBase app uses this technique to build an universal framework for developers to link their Xcode projects so that you can view your SQLite database contents while developing and debugging your apps.
Install the iOS Universal Framework
First, clone the GitHub repository and install it to make these framework templates available in Xcode.
> git clone https://github.com/kstenerud/iOS-Universal-Framework.git
> cd iOS-Universal-Framework
> ./Fake\ Framework/install.sh
> ./Real\ Framework/install.sh |
Create a new static framework project
The iOS Universal Framework GitHub page describes the different types of frameworks available that you can read more about, including real vs. fake frameworks, regular vs. embedded frameworks, and in what situations you may want to use them. In DevBaseHelpers’ case, we will create a real regular framework for easy distribution and without the need to distribute resources. Start a new Xcode project and select Static iOS Framework under iOS > Framework & Library.

Create a target for Mac
I built DevBase with the intention to make it work for both iOS and Mac apps. Let’s create a target for Mac too. Click on the project in the left pane to show the project settings. Click Add Target in the middle pane, select Cocoa Framework under OS X > Framework & Library. I like to add iOS and Mac suffixes to my target to distinguish them. I can do that by just clicking on the target name and rename it.

I also like to rename the schemes to reflect the two platforms. You can do so by selecting Manage Schemes and clicking and renaming.

Add your code and resources
Your Xcode project now has two targets for iOS and Mac respectively, so you have to pay attention to which target(s) you add your code and resources to. A code or resource can be used in three ways:
- iOS only
- Mac only
- Both iOS and Mac
Assume we want to create a new class called Chloe. This class needs to work for both iOS and Mac. In addition, there are platform-specific functionalities related to this class. Hence, I add three classes and organize them in Xcode accordingly. I also make sure they are added to both iOS and Mac targets’ build phases correctly. Let’s add these three classes:
- Chloe_iOS
- Chloe_Mac
- Chloe
I add Chloe.m to the Compile Sources build phase and Chloe.h to the Copy Headers build phase for both the iOS and Mac targets, but only added Chloe_iOS.m and Chloe_iOS.h for the iOS target, and Chloe_Mac.m and Chloe_Mac.h for the Mac target.

Build the frameworks
Now that the framework project is set up properly for both targets, it is super easy to build them. Select the iOS target and hit ⌘-B, then select the Mac target and hit ⌘-B.

Understand the frameworks
According to the GitHub page, both the device and simulator destinations for the iOS target build the same universal binary, so it doesn’t matter which you select. The Products directory shows all the frameworks it can build:

For the iOS target, it also builds both a regular framework and an embedded framework. The implications are:
If your framework has only code, and no resources (like images, scripts, xibs, core data momd files, etc), you can distribute (your framework).framework to your users and it will just work.
If you have included resources in your framework, you MUST distribute (your framework).embeddedframework.
Use the framework in your app
After the frameworks are built, they are in the Products directory. You can right click on the Product in the left pane and select Show in Finder. To use it in your target app, you just drag the framework from the Finder to your app’s project.
If you need to expose your framework’s header files for your target app to use, you first need to move them from the Project section to the Public section of the Copy Headers build phase. For example, if I want my app to be able to use the Chloe class, I need to expose it as follow:

To include the header file, you just import it like so:
#import <Chloe iOS/Chloe.h> |
And then add the -ObjC flag to Other Linker Flags in your app’s build settings.

Your app should now be able to instantiate an object of class Chloe and call its instance methods.
One more thing…
After you update Xcode to a new version, you need to reinstall the iOS Universal Framework for projects that use it to compile. This is as simple as uninstalling and installing the templates again:
> cd iOS-Universal-Framework
> ./Fake\ Framework/uninstall.sh
> ./Real\ Framework/uninstall.sh
> ./Fake\ Framework/install.sh
> ./Real\ Framework/install.sh |
Restart Xcode and compile your project.
I just showed you how you can build an universal iOS framework to share code between your iOS and Mac apps. This same technique is used to build the DevBaseHelpers framework for DevBase. I will talk more about the design process for DevBase in my next post.