Umbrella Framework

Xcode12.4 - iOS Umbrella xcframework framework with xcframework sub projects

Some things to try:

  1. Make sure to have BUILD_LIBRARY_FOR_DISTRIBUTION set.

  2. Link the sub frameworks statically. If you are including the other frameworks using CocoaPods, make sure you specify use_frameworks! :linkage => :static.

  3. In your source files where you use the sub-frameorks, write @_implementationOnly import SomeFramework .

iOS Umbrella Framework - codesign problem


The Solution

The problem is that the script was starting when the pod wasn't already attached.
The script should be run when all the pod jobs are done.

I wrote a full guide to build an iOS Umbrella framework!

The solution I found is the following:

1) Step one:

In the podfile of the integration project (not the umbrella project) add the following line of code where you add dependencies:

script_phase :name => 'Sign', :script => './sign.sh'

like this:

target 'yourTarget' do

# Pods for sdkInteTest
#your pods goes here

script_phase :name => 'Sign', :script => './sign.sh'
end

2) Step two:

Than in the terminal at the root of your test Integration project:

In the terminal type:

touch sign.sh
chmod 777 sign.sh
open sign.sh

And in the script file add this code:

echo "Signing subframeworks"
pushd "${TARGET_BUILD_DIR}"/"${PRODUCT_NAME}".app/Frameworks/YOURFRAMEWORKNAME.framework/Frameworks
for EACH in *.framework; do
echo "-- signing ${EACH}"
/usr/bin/codesign --force --deep --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --entitlements "${TARGET_TEMP_DIR}/${PRODUCT_NAME}.app.xcent" --timestamp=none $EACH
done
popd

echo "BUILD DIR ${TARGET_BUILD_DIR}"

remember to rename your framework name.

In this way you are telling to CocoaPods to run a script phase after the pod installation.
Unfortunately this is a "client" solution, I tried to find a solution to apply at framework level without any luck.

How to create an umbrella framework in iOS SDK?

We all know that creating umbrella framework is highly discouraged by Apple. But apple also says it’s possible via Xcode. https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/CreationGuidelines.html#//apple_ref/doc/uid/20002254-BAJHGGGA

I achieved creating umbrella framework via these simple approach on Xcode 5.1. We just need to do take care of some special configuration to linking sub-framework to umbrella framework. Here was my approach:-

  1. Install real Static iOS Framework on Xcode 5.1 from the method described here:- https://github.com/kstenerud/iOS-Universal-Framework.

Now the ‘Static iOS Framework’ can be created using the new option in Xcode.

Sample Image


  1. Create a Static iOS Framework and change the Target-> Build Settings-> Architectures-> Architectures settings to Standard architectures. This will create the framework with all the Standard Architectures.

Sample Image


  1. Adjust Public Header files in Target-> Build Phase-> Copy Headers. We can set the header file visibility here.

Sample Image


  1. Link SubFramework to UmbrellaFramework in Target->Build Phase -> Link Binary With Libraries. We may also need to link other standard framework depending on our use.

Sample Image
Sample Image


  1. We may also need to add Bundle Resources in Target-> Build Phase-> Copy Bundle Resources if we need.

Sample Image


  1. We may also need to add -ObjC to Target-> Build Settings->Linking-> Other Linker Flag, as we may need to load a large subFramework where there are many categories to load or need to load additional frameworks also.

Sample Image


  1. Add Copy File using Target-> Build Phases-> +-> New Copy File Build Phase.

Sample Image


  1. Change it’s Destination to Frameworks and add SubFramework.framework there. This will copy SubFramework to Umbrella Framework.

Sample Image
Sample Image


  1. For the demo I Added two demo methods in UmbrellaFramework class. One to demonstrating umbrella framework method call and one for calling subFramework method.

Sample Image
Sample Image


  1. Select iOS Device and Archive the UmbrellaFramework project from Menu->Product->Archive. This will create our umbrella framework and that’s all.

Sample Image


  1. Now it’s time to create a new demo project, and link it with UmbrellaFramework.

Sample Image


  1. Just import UmbrellaFramework header and call the two methods. It will show the Hello messages in log window.

Sample Image

Why are umbrella frameworks discouraged?

Umbrella frameworks only make sense if you are the only distributor of all the involved frameworks, and you will be packaging all the frameworks together as a single versioned package which will be upgraded together. If that is your situation, then that's fine, but this is a very unusual situation. In the Cocoa development world, it is exceedingly unusual for anyone but Apple to be in this situation.

To the first point, umbrella frameworks only make sense if you are the only distributor of the given frameworks. For example, say that you wanted to include libcurl as part of your umbrella framework. Now some other packager also wants to include libcurl as part of his umbrella framework. Now we have a link-time collision that can lead to either link errors or worse, undefined runtime behavior. I've chased these down myself. They're extremely unpleasant. The only way to avoid this is for there to be only a single version of each framework/library. Umbrella frameworks encourage the opposite.

Even if you are just breaking up your own code into subpieces, this means that other vendors might use your sub-frameworks in their own umbrella frameworks, leading back to the same problem. Remember, if you say it's ok for you as a third party to use umbrella frameworks, then it's ok for other vendors too.

To the second point, umbrella frameworks only make sense if you control the versioning of all the sub-frameworks. Trying to patch one piece of an inter-dependent set of frameworks is almost always a disaster in my experience.

The OS vendor has an unusual situation due to the size and ubiquity of their system. Things that make sense at one scale often do not make sense at another. NSResponder is completely correct about that. The trade-offs are different when you're providing a complete, multi-thousand package environment that is the basis of every program written for the platform. But even Apple has only a handful of large umbrella frameworks, and they are always wrappers around libraries that they provide and control the version of. This is mostly to simplify the work of developers who would otherwise have to chase down dozens of libraries and frameworks to get something to compile. No third party has that situation, and so it is very rare that a third-party needs this solution. Asking your customer to link two libraries is completely different then asking them to link 20. If you're providing 20 frameworks that all work together and you control, then maybe you should use an umbrella, but also maybe you have too many frameworks for a third party.

Most of my discussion here is in terms of OS X. On iOS it is a non-issue for third-parties. Static libraries must never link other static libraries due to the collisions that will certainly occur.

In theory, most of the issues I've discussed here a fundamentally technical limitations of the linker. The linker doesn't have a good way to manage multiple versions of libraries and so collisions are a serious problem. .NET assemblies try to provide more flexibility around this. I'm not familiar enough with .NET development to say whether this has been successful or not. My experience with large multi-component systems is that simpler, less flexible solutions are best for most problems. (But then, the grass is always greener....)



Related Topics



Leave a reply



Submit