Are umbrella frameworks possible/discouraged?

I want to release a Framework F, containing several other frameworks (such as Realm, Appetitive, Cocoalumberjack, PhoneNumberKit) for use by app A.

According to this article: https://medium.com/@bittudavis/how-to-create-an-umbrella-framework-in-swift-ca964d0a2345

They write, without referencing a source: "Although Apple discourage creating umbrella framework". Is that true, do Apple discourage umbrella frameworks, if so why and is it a very strong discourage or a mild one?

If not discouraged, then how can this be achieved with Xcode 16? I've been attempting to follow a few tutorial to achieve this, such as https://medium.com/john-lewis-software-engineering/adding-a-third-party-framework-inside-a-first-party-framework-in-xcode-3ba58cfd08da

however so far without any success. This last article mentions the Link Binary With Libraries section, which doesn't exist in Xcode 16.

There's the Frameworks, Libraries, and Embedded Content section where I have been attempting to add the frameworks into my Framework F (choosing Embed without Signing).

I'm able to successfully build Framework F, but when app A attempts to use it (adding F to the Frameworks, Libraries, and Embedded Content section with option embed and sign, or embed and don't sign, makes no difference) then I get run time errors about the umbrellaed frameworks not being able to be found.

They write, without referencing a source: "Although Apple discourage creating umbrella framework". Is that true, do Apple discourage umbrella frameworks, if so why and is it a very strong discourage or a mild one?

Here's a citation for that, from Technote 2435:

An umbrella framework is a framework bundle that contains other frameworks. While it is possible to create umbrella frameworks for macOS apps, doing so is unnecessary for most developers and is not recommended. Umbrella frameworks are not supported on iOS, watchOS, or tvOS.

While that technote is older, that advice is still relevant. It's quite normal today for an app to have a large dependency tree, and that's a scenario where it's easy to get into trouble. Consider an example app that looks like this:

App
├── Library1
│   └── LibraryA-1.0.0
└── Library2
    └── LibraryA-1.0.3

Let's further assume that LibraryA in that diagram is written in Objective-C, or Swift. What happens when the app launches is that the system needs to load and map all of the symbols each binary contains. Since Library 1 and Library 2 both depend on Library A, but there are two different implementations, the same symbols are going to get loaded, twice. This creates a runtime conflict of undefined behavior of which implementation gets used — if Library 1 calls LibraryA.method1(), it might actually call into the method implementation from LibraryA-1.0.0 ... or it might wind up calling into the implementation from LibraryA-1.0.3, of Library 2, because which one gets called is the undefined behavior. So now you have the possibility of Library1 calling into a library version that it didn't test against and is controlled by some other library that may not even be maintained by the same organization. Pushing this even further, let's say that Library 1 calling into Library 2's copy of Library A crashes. The author of Library 1 has no ability to reproduce or debug, because the crash is entirely dependent on a copy of LibraryA loaded into the same process that they have no control over. Yikes!

One way the above could be dealt with is if both Library1 and Library 2 declare a dependency on Library A through a Swift Package, using a semantic versioning scheme, such as 1.0 to accept any bug fix version of 1.0. At build time, the system can see that both libraries depend on Library A, and resolve that the most recent version, such as 1.0.3, so that everyone gets the same implementation, and that Libraries 1 and 2 do not need to bundle their own version specific copies, and Library A can be a sibling. Then the app structure looks like this, with Libraries 1 and 2 both pointing at their LibraryA sibling:

App
├── Library1
├── Library2
└── LibraryA

I've talked to a lot of developers about this subject over many years, and the specifics of any situation matter a lot. This is just one example, with one solution, and there are many other situations that would need a different solution, but I hope it highlights some of the issues that a dependency tree cast as an umbrella framework can create.

— Ed Ford,  DTS Engineer

Are umbrella frameworks possible/discouraged?
 
 
Q