Dynamic framework with embedded static frameworks within an XCFramework

Hi there! I’m new to creating and distributing binary frameworks so thanks in advance for your patience if I’ve overlooked known solutions.

My goal is to distribute a single Swift XCFramework to customers that requires only a single import to allow access to all public classes and methods.

The current structure is an Xcode 12-backed workspace created by CocoaPods, which integrates one project that contains a binary framework (FrameworkA) and one project that is just raw code (FrameworkB). Within that workspace are three other projects, each dedicated to a single framework (frameworks C, D, and E), and a final project that is used to gather all these other dependencies and act as the single point of access (CustomerFramework).

There is an additional project (TestHarness) within the workspace to act as a basic way to run tests, confirm functionality, etc.

The structure looks something like this:

Workspace
  - CocoaPods static binary framework (FrameworkA)
  - CocoaPods normal code projects (FrameworkB)
  - FrameworkC project
  - FrameworkD project
  - FrameworkE project
  - CustomerFramework project
  - Test harness project

CustomerFramework works as expected when run within TestHarness. Additionally, I can successfully create an XCFramework that contains Simulator and devices frameworks of CustomerFramework.

However, compilation fails when I try to use CustomerFramework.xcframework in a separate demo app. The swiftinterface shows imports for the expected modules (FrameworkA, FrameworkB, etc.) but Xcode raises an error of “No such module ‘FrameworkA’”.

import CustomerFramework <-- “ Failed to build module 'CustomerFramework' from its module interface”

I’ve changed the dependent frameworks from dynamic to static, I’ve attempted to set custom header search paths to the dependent frameworks in the CustomerFramework project, I’ve tried to set custom framework search paths, I’ve tried (and failed) to create a custom modulemap, and I’ve tried what feels like every tip or trick found here, in the Apple dev forums, StackOverflow, and various blog posts.

I can’t use @_implementationOnly because CustomerFramework purposefully exposes types from dependent frameworks.

Is what I’m trying to do possible? Does anyone have reference values for how to correctly set header search paths? Maybe a real-world project example of something similar to this?

References:

3 Likes

Wow! This is an awesome compilation of a problem I ran into, too!
Anyone here has anything to help us out here? Please!

My finding so far are:
The problem with the "import" is that - when you look into the .xcframework dir - the .swiftinterface files contain framework/library import statements that seem to lead to compile errors when trying to compile to .swiftmodule.
I really don't know what I am saying here, but at least I sort of know a cause for a problem.

It would be nice if some export could explain all this mess.

I'm interested in this topic as well. I'm still a beginner in authoring frameworks and only recently learned about @_implementationOnly. I think there isn't a way to accomplish this without using @_implementationOnly, so maybe one solution would be to create wrappers around exposed types from your dependent frameworks so that those wrappers would be public and the dependent frameworks can be private, so customers would have to call your wrappers to access APIs from private dependencies instead of calling the APIs directly. This could allow you to use @_implementationOnly.

There could be other solutions. I hope there's more discussion about this.

I'm trying to implement this exact scenario within Xcode 14.3.1. Is this resolved? If not any pointers or articles that would provide insights into resolving this?

Thanks

I would also be interested in any updates (suggested solutions) to this.