15

I have this code base which is Objective C and Swift mix. Some places Swift uses Objective and and vice versa. I need to create a framework now based of off this codebase but do not want to include all the objective c files in my umbrella header. Here's my problem:

Inside my framework I still need to be able to use swift from objc and vice versa; but do not want to expose all those objc files that are being used internally by swift classes. Bridging header is not allowed in frameworks so all the headers needed by swift need to go in umbrella header.

I'm wondering if it's possible to have all the objc headers needed by internal swift code go in a file which would be my private umbrella header and all the files that I need to expose would go in public umbrella header.

Any suggestions?

puru020
  • 808
  • 7
  • 20
  • Hi, @puru020, have you found a solution for this? I have exactly the same problem and I can't find how to solve it. Thanks. – Daniel Jan 14 '16 at 12:33
  • I haven't. There doesn't seem to be a solution. What we decided to is to keep 2 sections in the umbrella header for public and private .h files. Once the framework is built we run a script that goes and deletes the private section of the umbrella header. – puru020 Jan 14 '16 at 17:57
  • Yesterday I've been searching for hours to find solutions to this problem. The major problem is the restriction of not being able to use a bridging-header in frameworks. For the case "private objc-header in Swift", I stumbled upon the definition of a private module, a CLANG-feature. But unfortunately, this seems to be there for exposing private headers to other frameworks, rather than using private objc-headers in Swift. Though I believe there's a reason to the problems, as interoperability seems to be important to Apple. I would appreciate a clarifying answer. – Felix Lieb Jan 29 '16 at 13:41
  • If you need to completely hide those private .h files from users that will receive your framework then the only way to do it is to make them public (add them to public umrella header as usual) and remove them from the framework and from umbrella header after building it. You can do that by creating a special script in run script step added to the build process to make it automatic. – Leszek Szary Oct 05 '20 at 12:05

1 Answers1

4

I am successfully using explicitly declared modules as a solution of sorts for this issue for the Objective-C -> Swift case. I have not separated the module declaration into a separate private module map but declared both the framework module and an explicit module inside the same modulemap because of the concern raised in one of the comments to the question (I wasn't sure if or how it is possible to use the header generated by the private module map inside the same framework).

Here's an excerpt of the modulemap I have defined for my MPFoundation.framework, which includes an explicit module MPManuscriptCompiler_Protected that imports the header "MPManuscriptCompiler+Protected.h" which is not included in the umbrella header for the framework:

framework module MPFoundation {
    umbrella header "MPFoundation.h"

    export *
    module * { export * }

    explicit module MPManuscriptCompiler_Protected {
        header "MPManuscriptCompiler+Protected.h"
        export *
    }
}

I then use this explicit module MPManuscriptCompiler_Protected in my Swift subclass which is present in the same framework like so:

import MPFoundation.MPManuscriptCompiler_Protected

My solution is really technically just a workaround though: for this to work, "MPManuscriptCompiler+Protected.h" can be marked a private or project level header in the framework, so it will not be visible in the umbrella header and will not be available for header based imports with its filename. So, this works around having to include this header in the umbrella header.

However, the module created this way is publicly exposed in the framework and available for eyes that should not see it. I did not investigate this further as practically this solves the issue well enough (am yet to hit issues where I would have by accident imported that protected header where it wasn't supposed to be imported).

mz2
  • 4,672
  • 1
  • 27
  • 47
  • Does this stop the client of your framework from importing your private classes like the way you have done? This is what has worked for me: https://github.com/danieleggert/mixed-swift-objc-framework – puru020 Apr 27 '16 at 00:52
  • Sort of: the header itself can actually be set to be private instead of public (this contradicts my answer above – will adapt it)… so for header based imports it's not available. However, as a module it is available in this form for outside clients, which has been acceptable for me as I have not had then to mess about with a separate folder & separate module map & the extra build configuration keys. Your solution sounds more correct though. – mz2 Apr 27 '16 at 02:21