Include of non-modular header inside framework error - ios

I realize this is a common error and has been asked several times but I am unable to resolve it after trying several different things based on others' answers.
I am creating a framework project (Obj-c) which uses another third-party framework. In MyFramework's umbrella header, I have the import statement of third-party framework. When I packaged my framework and included it in another iOS project, it fails to build with this error.
Things I tried:
Turned ON "Allow non-modular includes in Framework modules"
Added the umbrella header of the third-party framework as a "Public" header
Please advise what is missing here. Thanks in advance!
Here's the Exact Error:
Include of non-modular header inside framework module
'MyFramework.TestManager':
'/TestApp/WindowsAzureMessaging.framework/Headers/WindowsAzureMessaging.h'
Also, from the path it looks like it is trying to search for it in the TestApp project, whereas it should refer from the Framework.
I imported the Azure Messaging Framework in the Umbrella header as shown below:
#import <WindowsAzureMessaging/WindowsAzureMessaging.h>

I was able to reproduce your error. I looks like the WindowsAzureMessaging header and all other headers it refers are not made to be used in a modular framework umbrella header, because it uses "user" imports instead of "system" imports relative to the framework, and also it doesn't have the modulemap file.
You have several options:
adapt their code and make it build as a module (make it "modular").
not include it in the umbrella header (avoid referencing things from it there), but link it and use directly in the app and your framework.
instead of using the file framework as a separate entity, you could take (copy) their source code (m and h files) and compile into your framework, and then expose some headers as your own headers.
I think that option 1 is the right way to go. It is not hard, and if you manage to do that, think about making a pull request for their repo, because this is going to benefit everyone.

Related

Custom framework cannot find other pod that required Bridging-Header file: "No such module 'InsiderMobile'"

Currently we are developing a custom framework which need to use InsiderMobile cocoapods. According to this guideline, we will need o create Bridging-Header File to use InsiderMobile. However, Bridging-Header or Umbrella file did not work inside our framework so we have to use MapModule with Build Settings/Import Paths method, then the framework compile just fine.
The actual problem occur when we try to apply our framework to an application. The framework recognize all other pods except InsiderMobile. Here our current settings:
We got both our custom framework and InsiderMobile in Pods folder,
Our custom framework is Embed,
MapModule with Build Settings/Import Paths method is also apply,
Here is some methods that we've already tried:
pod install again, delete derived data, clean and rebuild project,
Manually edit custom framework -umbrella file, but bump into new error: "Include of non-modular header inside framework module ", also try to set Allow Non-modular Includes In Framework Modules in Build Settings to Yes
Also Embed InsiderMobile framework,
None of these above methods solve the problem. Is there anyway to allow our custom framework to import InsiderMobile? Thanks in advance.
In case it's helpful, i have found a way to temporary solve this issue. Not the best but help us unstuck the developing process. Basically, i have been trying to work with .modulemap method the whole time, you can find the docs here. Then i found this topic, and there this guys repo. I just follow the repo with a little change on the .modulemap file and everything work fine for me. Here's my .modulemap file:
module InsiderMobile [system] {
// Framework complier
// header "../../../../Pods/InsiderMobile/InsiderMobile.framework/Headers/Insider.h"
//App complier
header "../../../../../../Pods/InsiderMobile/InsiderMobile.framework/Headers/Insider.h"
export *
}
Cause .modulemap file directory might change when it go remote, so i have to change to suitable path before deploy it. I know it inconvenience but it work for now.

How to use Obj-C Framework code in Swift Framework?

How to use Obj-C Framework code in Swift Framework?
Is it possible or I need to mix them in a single Framework?
I have code for both Frameworks. I connect them manually without CocoaPods, Carthage or Swift Package Manager. Bridging header cannot be used inside of a Framework, only in App Target. Google says that I need to use modulemap file. In all examples I found they create their own modulemap files and put them near the Swift framework code. I tried to use both my own modulemap file and existing one inside ObjCFramework.framework/Modules. I use them by adding a path to the modulemap file to SWIFT_INCLUDE_PATHS build setting of my Swift Framework. I also tried to #import Obj-C Frameworks Ubrella Header to Swift Frameworks Ubrella Header with no luck. Of course I added the Obj-C Framework target to my Swift Framework target dependencies, the framework itself to Frameworks and Libraries and the path to it to Framework Search Paths. I didn't put anything to Header Search Paths to avoid "Include of non-modular header inside framework module", but that didn't help. CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES build setting doesn't help too. DEFINES_MODULE is set to YES.
Now I'm in endless loop of several errors:
Include of non-modular header inside framework module 'ObjCFramework': '/Users/bond/Library/Developer/Xcode/DerivedData/SwiftFramework-aqidpocynynsvdgtrqwukanwqkxf/Build/Products/Debug-iphoneos/ObjCFramework.framework/Headers/View.h'
Module 'ObjCFramework' was built in directory '/Users/bond/Library/Developer/Xcode/DerivedData/SwiftFramework-aqidpocynynsvdgtrqwukanwqkxf/Build/Products/Debug-iphoneos/ObjCFramework.framework' but now resides in directory '/Users/bond/Library/Developer/Xcode/DerivedData/SwiftFramework-aqidpocynynsvdgtrqwukanwqkxf/Build/Products/Debug-iphoneos/ObjCFramework.framework/Modules'
No such module ObjCFramework
underlying Objective-C module not found
In brief this is described here: https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_objective-c_into_swift, "Import Code Within a Framework Target" chapter.
If the Defines Module setting is turned on in your framework target, modern Xcode puts Modules folder in the framework, with Swift versions of all you ObjC public interfaces, making ObjC stuff available either for external Swift code that links your framework or Swift code of the framework itself.
This does not depend on whether your framework target contains any swift code.
Just add you ObjC header to framework target, mark it as Public in "Target membership", include in framework Umbrella header and build.

Swift framework umbrella header - Include of non-modular header inside framework module

I'm trying to include openssl framework into the swift framework I'm building (I created it with cocoapods - pod lib create) . When I go to default umbrella header and import some header form openssl framework I get Include of non-modular header inside framework module.
I tried everything to fix this (checked questions form stackoverflow), including solution with allow non-modular includes.
I was using openssl framwork in normal swift projects by importing it inside bridging header, and I had no problems like this.
After long time I finally found a solution that worked for me.
Include of non-modular header inside framework module means that you must make framework you want to include modular. That can be done by creating custom module map, where you define new module for desired framework.
You can find here how to create custom module map.
Important thing to note is that I managed this only with dynamic frameworks. Other important thing is you must use absolute path in module map (e.g. header "/Users/User1/Documents/Project/TestProject/Sample.framework/Headers/sample.h"

Xcode can't find header file

I am trying to make a framework for my project. Into my framework I added the path of my header files to target>Build Settings>header-search path. After that I added this framework to my project by Build Phases>Link Binary With Libraries.
When I want to import the header file which I included in my framework, I get a .h file not found error. Is what I'm trying to do possible? Or am I missing anything?
I created framework like that;
Opened new project as iOS>Framework&Library>Cocoa Touch Framework
I didn't add any class, i just added header search path and library search path and linker flags. I don't think i did a mistake in this part because we do it in every project but first time i m doing this for framework. Then i pressed run and get my framework from Products.
I opened my project and added framework Build Phases>Link Binary With Libraries. I m able to import header file of framework like #import <myframework/framework.h>
After this i added framework also General>Embedded Binaries. Everything look normal but i cannot add headers to my project which i included to my framework with header search path. I have to use header search path because there is tons of headers, i cannot add all of them to my Xcode.
Make sure you all Public Header appears in Public Section else drag and drop .h file to public
Everything look normal but i cannot add headers to my project which i included to my framework with header search path.
It sounds as though you're expecting all the headers that can be found at the path specified by your header search path will become part of your framework, so that if there's a header named SomeHeader.h in your search path, it will be built into your framework and you'll be able to import it into client projects like:
#import <MyFramework/SomeHeader.h>
But that's not the case at all. If you want your framework to provide SomeHeader.h, you need to add that file to the project and, as Meghs Dhameliya already pointed out, you need to specify SomeHeader.h in the Public Headers portion of the Headers build phase. This will make Xcode copy the header file into the framework so that clients of the framework can import the header file. It's not clear that that's what you really want, though... in comments you wrote:
There is a lot of headers in another path. I have to use header search path unfortunately. Kind of company rule.
So it sounds like all projects in your company specify the same header search path so that they have access to these header files. If that's true, then there's no reason for projects to need to #import them from your framework, but in that case it's not clear what the actual problem is. Or, perhaps you're creating the framework so that client projects can get the headers from your framework instead of having to reference the header search path. In that case, you will need to add those headers to the project and specify them as described above.

How to import private framework headers in a Swift framework?

I have an Objective-C framework (framework A) that exposes some public and some private headers. The public headers are also declared in the framework's umbrella header. I have a second Swift framework (framework B) that links with the Objective-C framework.
Now, if I want to import the public headers of A in B I simply need to do an import A.
But how do I go about importing the private headers?
I know a bridging header is not an option since that's not supported for frameworks. Do I need to somehow create a separate umbrella header for the private headers?
You need to modify framework A, So that it export a private module.
Create a private module map file in A project. This would be something like this:
A/private.modulemap:
explicit module A.Private {
// Here is the list of your private headers.
header "Private1.h"
header "Private2.h"
export *
}
In the "Build Settings" of framework A target, search "Private Module Map File" line, and make that:
$(SRCROOT)/A/private.modulemap
Do not include private.modulemap file in "Compile Sources". That causes unnecessary warnings.
Clean and Build framework A target.
In framework B Swift files. you can import the private module like this:
import A
import A.Private
It is some time since this question was posted. The accepted answer is very good, and as far as I'm concerned it is a common approach.
The problem is, it is not really "private". You can do this inside your framework to access the "private" part:
// Framework A Swift file
import A.Private
But If you use framework A in an app (or you ship it to your client), he can still do:
// Client App Swift file
import A
import A.Private
// access "private" framework methods and classes
I was trying to resolve that, as I had recently a situation when I needed to hide it from users (closed source framework) - I just could not let anyone access it, as it was a threat to SDK integrity.
I found a solution to that problem, but a bit too complex to paste it here as a whole.
I made a post about it no medium. Maybe it will help someone checking that problem, that's the link to my article:
https://medium.com/#amichnia_31596/creating-swift-framework-with-private-objective-c-members-the-good-the-bad-and-the-ugly-4d726386644b
As noticed by Andrzej Michnia in his answer the problem with "private module map" solution is that it is not really completely private and those "private" headers still can be seen by someone as they are still included in our framework. If someone opens compiled framework with such "private" module he will still see all .h files that you hidden.
If we need to hide some objective-c headers in our swift framework completely from other users then another possible method to do that will be just to make them public and remove them from our framework after building the framework manually or with a bash script.
You could create a separate header file for example "InternalHeaders.h" where you import all headers that you do not want to expose. Then import this InternalHeaders.h in public umbrella header of your framework. Make all headers public so that you can compile everything. After you build your framework simply remove "import InternalHeaders.h" from public umbrella header and remove all headers that you do not want to expose manually or with a bash script or in run script build phase and thats it.
Still not a perfect solution but in some cases it might be much easier and faster that writing protocols in swift to match every objective-c interface as proposed in other answer.
My situation may be particular to my setup, but I'll offer it here, in case it helps someone else. I also have an Objective-C framework (framework A) with private headers that I need to use in a Swift framework (framework B) that links it. Some additional details:
Each framework is in a separate project in the workspace
The project uses CocoaPods
The podspec defines the following dependence relationship between the two frameworks:
s.subspec 'FrameworkA' do |cs|
cs.vendored_frameworks = "lib/FrameworkA.framework"
end
s.subspec 'FrameworkB' do |ts|
ts.dependency 'FrameworkA'
ts.vendored_frameworks = "lib/FrameworkB.framework"
end
The solution offered by #rintaro works great for me when running in Xcode, but once the Pod is deployed, FrameworkB is unable to find the private headers using the paths in the private modulemap that lives in FrameworkA. What worked for me was to use a relative path to the PrivateHeaders dir in the private modulemap:
module FrameworkA_Private {
header "../FrameworkA.framework/PrivateHeaders/Private.h"
export *
}
This works in Xcode and in the final product installed using CocoaPods. It's a little bit hacky, since it references a folder in the final build product, and I wouldn't be surprised if there's some other way to tell CocoaPods how to preserve these paths, but whatever it is, I haven't found it. This solves the problem for now.

Resources