How to create an Umbrella Framework in Swift?

Using Xcode 9.2 and Swift 4

Bittu Davis
5 min readDec 20, 2017

Although Apple discourage creating umbrella framework, there are situations where developer is asked or required to create the same.

So what is an umbrella framework? Why is it used?

Umbrella frameworks are frameworks which contain frameworks within. This can be used in several situations. When you are developing a custom network class which require a different parsing logic or need to implement a custom online payment functionality, you might create an umbrella framework.

Here, we will start with creating a simple framework and we add this framework to another framework making it umbrella framework. We will then create a sample project to incorporate umbrella framework.

Creating sub framework

1 Select Cocoa Touch Framework and give it a name. Here I am giving name as SubFramework

2 Create an Aggregate Target for this framework, so that we can make this as Universal Framework.

3 From the Aggregate target go to Build Phases and create New Run Script Phase

4 Add this script to Run script so that it can build a Universal Framework with full bitcode enabled.

#!/bin/shUNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal# make sure the output directory existsmkdir -p "${UNIVERSAL_OUTPUTFOLDER}"# Step 1. Build Device and Simulator versions. This also include the full bitcode generation of frameworkxcodebuild BITCODE_GENERATION_MODE=bitcode OTHER_CFLAGS="-fembed-bitcode" -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean buildxcodebuild BITCODE_GENERATION_MODE=bitcode OTHER_CFLAGS="-fembed-bitcode" -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build# Step 2. Copy the framework structure (from iphoneos build) to the universal foldercp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"# Step 3. Copy Swift modules (from iphonesimulator build) to the copied framework directorycp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directorylipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"# Step 5. Convenience step to copy the framework to the project's directorycp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"# Step 6. Convenience step to open the project's directory in Finderopen "${PROJECT_DIR}"

5 Go to Build Settings from Aggregate Target and add -fembed-bitcode to Other C Flags. If you don’t give this flag, you might not be able to archive the app with this framework.

6 Create a New Swift file and write your own operations. Here, I have created file named SubFrameworkHome and added methods as below. Make sure your class is open , so that Umbrella Framework can access it.

open class SubFrameworkHome: NSObject {       open class func sayHello() {
print("Saying hello from Subframework")
}
}

7 Now select Aggregate Target from the build panel and build. You will be seeing .framework being generated from the run script. Copy the framework and keep it ready for use of Umbrella Framework.

Now that we got sub framework ready, let’s create Umbrella Framework.

8 Same as we did for SubFramework , Create new Cocoa Touch Framework and add Aggregate target to same. I will call this framework as UmbrellaFramework

9 Repeat steps 3 4 and 5

10 Copy SubFramework.framework to root folder of Umbrella Framework project.

11 Create a New Copy Files Phase in Aggregate Target → Build Phases and select SubFramework.framework from root folder. Make sure you add Destination as Frameworks

12 Select Framework Target and add SubFramework.framework in Link Binary with Libraries and Copy Bundle Resources. Create a New Copy Files Phase and add the same to list. Make sure you enable on Code Sign on Copy

13 Create a New Swift file and we will call methods from subframework there. I created a class like below.

import SubFrameworkopen class UmbrellaFrameworkHome: NSObject {     open class func sayHello() {
SubFrameworkHome.sayHello()
print("Saying hello from Umbrella Framework")
}
}

I made both class and method as open so that App can invoke Umbrella Framework functions.

14 Now select Aggregate Target in build panel and build.
You will be seeing UmbrellaFramework.framework got generated in root folder.

There you go. This is Umbrella Framework.

Now that we are done with Umbrella Framework, we need to implement the same in an App.

15 Create a New Single View App. Copy UmbrellaFramework.framework to root folder of App.

16 Click on App Target → Embedded Binaries → Add the framework to it. It will automatically be placed in Linked Frameworks and Libraries

17 Now go to Build Settings → Framework Search Path → Drag and drop the Framework to it. You should also explicity mention the Frameworks inside the Umbrella framework. See below for reference.

18 Do the same for Project Settings.

19 Now App target → Build Phases → Create a New Run Script Phase and add this script to it.

pushd ${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app/Frameworks/UmbrellaFramework.framework/Frameworksfor EACH in *.framework; doecho "-- signing ${EACH}"/usr/bin/codesign --force --deep --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --entitlements "${TARGET_TEMP_DIR}/${PRODUCT_NAME}.app.xcent" --timestamp=none $EACHdonepopd

This script is done to make sure the Code Signing is done in subframeworks too. If not given you might face certificate issues in archiving the app with Umbrella framework.

20 You can import Umbrella framework to your required Viewcontroller. The one which I created look like this:

import UIKitimport UmbrellaFrameworkclass ViewController: UIViewController {      override func viewDidLoad() {
super.viewDidLoad()
UmbrellaFrameworkHome.sayHello()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

Here the result on launching ViewController is:

Saying hello from Subframework
Saying hello from Umbrella Framework

Please find the github link for this complete article here:
https://github.com/bittudavis/UmbrellaFramework

Got queries? Comment below.

--

--