Missing Required Module - Custom Framework - ios

I created a Cocoa Touch Framework, this framework contains mostly Objective-C codes, my goal is to keep these objective-c codes private, so I added an adapter class in Swift as a middleman between the consumer and my objective-c codes. To do this, I created module to import my objective-c classes and allow my swift class to access these objc classes. I used this guide and clang doc.
So with this I am able to access my objc codes inside my Swift class.
import PrivateObjc
public class SwiftClass{
public func createPersonClass() -> ObjcPerson {
return ObjcPerson()
}
}
The code snippet above works just fine, within my framework atleast. But when I try to use my framework in another project, I get this error:
Missing required module 'PrivateObjc'
I've seen similar posts here in SO but most of them are using Carthage or Cocoapods, some about CommonCrypto. This question is about a custom framework created from scratch. Can anyone enlighten me how to accomplish this? Thanks!

Related

ProjectName-Swift issue - Cannot find protocol declaration for 'ASAuthorizationControllerPresentationContextProviding'

I'm now using Swift class in my existing Object-C project to integrate sign in with apple.In my Swift class, I'm using ASAuthorizationControllerPresentationContextProviding delegate. However, when ProjectName-Swift.h is generated, an issue in ProjectName-Swift.h file shows that Can't find protocol declaration for 'ASAuthorizationControllerPresentationContextProviding'. Works well in my pure swift project but can't work with mixed project I have.
ProjectName-Swift.h

Useing modulemap is in the swift framework to bridge the OC, and the missing required module is reported in project

I created a swift framework, and created a module.modulemap file, and included a Test.h file.
module Test {
header "Test.h"
export *
}
Then I set the import path in swift complier - Search Path like this
${SRCROOT}/SwiftFramework
Next I used this Test file in the swift file.
import Test
public class SwiftFramework: NSObject {
#objc public class func test() {
Test.test()
}
}
I created a project, added swiftframework, and it can run successfully. But when I change a computer or send the framework to someone else to use, will report 'Missing required module 'Test'' in project, The xcode version is the same,how can I solve this problem?
I had a similar problem recently (swift frameworks) and it seems like there's no way around this at the moment. This is a lot easier to deal with if there's a dependency manager involved (eg cocoapods) coz it will implicitly resolve those dependencies.
This is also the case with Facebook's iOS SDK. Eg: If you include FBSDKLoginKit as a pod, it will also fetch FBSDKCore. But if you include FBSDKLoginKit.framework in your project, it will complain that FBSDKCore wasn't found.
https://github.com/facebook/facebook-ios-sdk

iOS Swift framework: How to import Objective C code into swift framework properly?

I have an umbrella header called
MyApp-Swift.h
I've imported the following class "AFHTTPSessionManager.h" in the umbrella header.
I made the umbrella header public in build phases and I also made sure to set Define modules to yes.
However, in my swift framework I am still getting the following error
Use of undeclared type 'AFHTTPSessionManager'
I don't know why this is continuing. I thought swift would automatically pick up my Objective-C import. Any tips or suggestions are appreciated.
I tried following this source
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_82
,but it didn't work for me. This is very fusterating.
This is the swift code that causes the error.
import Foundation
class MyApp {
private var manager: AFHTTPSessionManager?
}
The thing is, brigding header doesn't work for Framework targets. Solution is to create module map target to build module map for needed ObjC framework.
Here is example for CommonCrypto: https://stackoverflow.com/a/42852743/1840136; in your case difference should be that script line
header "${SDKROOT}/usr/include/CommonCrypto/CommonCrypto.h"
will be replaced with path to AFNetworking headers (I'm not sure if you're placing 3rd party libraries just within project or getting from pods, so check by yourself).

Import Swift Framework in Objective-C Project - Error - Unknown Type Name

I've been wrestling with this specific issue for a while now. Basically I've added a framework BigNerdRanch CoreDataStack using Carthage.
But I've been having issues of using the said framework on my Objective-C codes. My project is an Objective-C project in which I recently added Swift codes and Swift frameworks.
So far I've been able to use Swift frameworks in my Swift codes with no problems. But once I started using the said Swift frameworks on my old Obj-C, specifically AppDelegate.m, I keep getting compiler error no matter what.
From what I understand I have to import it like this:
#import <CoreDataStack/CoreDataStack-Swift.h>
In which I did on AppDelegate.m.
I also have the following setup on my project:
Project Target Setup:
Build Settings for Swift Compilation:
I've been seeing some answers in StackOverflow to add public to the classes. But I'm unable to do so since the imported Frameworks are self-contained and only contains Headers for me to see in the XCode project.
Thanks for the help guys.
You added a framework written in swift, if they don't enable support for Objective C, you can't use it in your objective c code.
However, you can create a class in swift, which will be used as a mediator between the framework and your ObjC classes.
#objc class coreDataStackConvertor: NSObject {
func createStack(arg: Type) {
// Code which uses the real CoreDataStack
}
}
From you objective c classes, you can use the methods in the convertor class.

Objective C classes within an iOS Swift-based dynamic framework

Situation:
I've got an iOS dyanmic framework written in Swift. I've also got a bunch of classes written in Objective C that I would to use within my Swift classes (some are public, some are private). However, I would like the Objective C classes to not be exposed to projects using my framework.
What I have tried:
Umbrella Header
From what I understand, I should import using #import header.h in my umbrella header file, which is usually FrameworkName.h, and then make sure all the Objective C header files that I wish to include in my Swift classes are to marked as "Public", under Build Phases -> Headers.
Doing this, however, automatically exposes the project using my framework to all the private Objective C classes that the framework uses.
Module Mapping (with separate module)
Because of this, I've looked into using module mapping, which is documented here. I've looked at posts by other users such as this and this, as well as this Github repo.
I successfully got the following working:
//SharedClasses/module.modulemap
module SharedClasses {
}
//SharedClasses/module.private.modulemap
module SharedClasses.Private {
header "header.h"
export *
}
The problem is that in my project (that has this framework imported), this:
import Framework
import Framework.SharedClasses
is allowed, and subsequently the "hidden" Objective C classes are exposed. Perhaps this is just how modules work? Is there a way to make them truly private?
Module Mapping (with framework private module)
Also, I've tried creating a module.private.modulemap file at the root of my framework with the following contents:
explicit module Framework.Private {
header "header.h"
export *
}
and then linking it my target's build settings under MODULEMAP_PRIVATE_FILE. However, when I do import Framework.Private in my framework's Swift classes a compiler error is thrown:
"No such module 'Framework.Private'
I don't understand why this error is occurring.
Module Mapping (with private header)
I noticed that in the Clang docs, a private specifier is mentioned:
A header with the private specifier may not be included from outside the module itself.
My understanding is that since all the Swift classes in my framework are already part of the module Framework, if I create a module.modulemap file with the following:
framework module Framework {
umbrella header "Framework.h"
private header "header.h"
export *
module * { export * }
}
then everything should be working! The Objective C headers are only accessible within the module (i.e. the framework's Swift classes), and aren't exposed to any project using the framework. Cool, but it doesn't work...the compiler just doesn't recognise the Objective C classes. No other errors are thrown, but you can't use the headers, so it's like you didn't include the headers in the first place.
WHY? And what is the private specifier for then?
Soo, reiterating my original question:
Is there any way to import Objective C headers for use in Swift classes, within an iOS dynamic framework, while keeping them private and not accessible from any project using said framework?
Thanks for reading, and sorry for the long post. It's been a long day (and night)...
The quick answer is you can't :) Even if you declare "private" modulemap, it can be always imported by your framework users. Please note, that usually, it is not a concern, especially with open source. You just say "this is an internal module, don't use it".
But (there is always but) - you can have behavior, that effectively works the same - allows you to use your Objective-C classes withing same framework target, without making them public. It works in closed source setup - I have a dynamic framework shipped to external parties, that has a purpose of revealing as less about its construction as possible.
The case a bit too complex to paste everything here. I'm adding a link to my article about the topic. That's a general idea:
Mimic your Objective-C classes with Swift protocols (manual work needed)
In your swift code use these protocols
Expose internally these Swift protocols to Objective-C (manual work needed)
Adopt these protocols by ObjC classes
Create in Swift and expose in ObjC a factory, that will create instances of these protocols
Create in the factory methods, that will allow you to register concrete types, and expose them to ObjC
Register ObjC types from Objective-C code in the Swift factory
Use the factory to instantiate ObjC classes, without actually exposing ObjC to Swift (hurray ;) )
Creating Swift framework with private Objective-C members. The Good, the Bad, and the Ugly
Github example project
You can find some method from this link.
Just create Folder (e.g.PrivateA) with module.modulemap where include all object headers you need to use in your Swift class.
e.g.
module $(ModuleName)Private {
header "header.h"
export *
}
in Swift,
you can use: import $(ModuleName)Private
so, default module exclude these headers when using import $(ModuleName).
From my experiment, test project can also import $(ModuleName)Private, but not found any useful code.
Try this way anyway.

Resources