Importing Swift Class into Obj-C in React Native module - ios

I am developing a new feature for a react native module (https://github.com/blackuy/react-native-twilio-video-webrtc) the thing is it is developed in Objective-C and I need to import a new Swift class.
What I've done so far:
Importing it with the name of the package, in this case #import <RNTwilioVideoWebRTC/RNTwilioVideoWebRTC-Swift.h>
Ensuring that Precompile Bridging Header is set to Yes
Setting Objective-C Generated Interface Header Name as RNTwilioVideoWebRTC-Swift.h
The problem is then i try to run the example app inside the module, it prompts an error RNTwilioVideoWebRTC/RNTwilioVideoWebRTC-Swift.h file not found
What am I missing? Thanks!

There are a few things to make sure that:
Check whether the bridging file is available in your project or not. If available, make sure that you have imported YourProductName-Swift.h in your bridge file. And if not, please create a bridge file.
Mark the class & methods with #objc to make them accessible in your Objective C code.
You can follow this answer for reference.

Archiving will be successful already tested
How to call a swift function (that could be in a swift framework also) in objective c project or react native project
it will work for react-native also
follow these steps :
Open Build Settings and check these parameters:
Defines Module : YES
in AppDelegate.h
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
#class KB;
#interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
#property (strong, nonatomic) KB *appkb;
#end
in AppDelegate.m
#import "AppDelegate.h"
#import "ProductModuleName-Swift.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self.appkb methodReceiveSwiftClass];
[self.appkb methodEvents:event prop:properties];
}
#end
KB.swift
import Foundation
// import framework if using a swift framework in objective c or react native native modules.
#objc public class KB:NSObject{
#objc public func methodReceiveSwiftClass(){
//write anything here....
}
#objc public func methodEvents(_ event: String, prop: String){
//write anything here
//func with params
}
}
ProjectModuleName-Bridging-Header.h
#import "React/RCTBridgeModule.h"
#import "AppDelegate.h"

Related

My custom native module is not present inside NativeModules object

So, i wanted to create a native module which will detect, if the app is running on emulator/simulator or an actual device.
Everything works fine on android, but i'm facing issue on iOS.
I have create a AbcModule.h and a AbcModule.m file
#import <React/RCTBridgeModule.h>
#interface AbcModule : NSObject <RCTBridgeModule>
#end
This is AbcModule.h
#import "AbcModule.h"
#implementation AbcModule
RCT_EXPORT_MODULE(GetDetails);
- (BOOL) xyzFunctn {
#if TARGET_IPHONE_SIMULATOR
return YES;
#else
return NO;
#endif
}
RCT_EXPORT_METHOD(xyzFunctn: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject) {
resolve self.xyzFunctn;
}
#end
This is AbcModule.m
Here i have followed the react native documentation for implementing the Native Modules.
But i'm consistently facing this error which says
"TypeError null is not an object, evaluating GetDetails.xyzFunctn"
I have went through several solutions and articles but nothing seems to be working here.
Need help guys!
from the docs
If you do not specify a name, the JavaScript module name will match the Objective-C class name, with any "RCT" or "RK" prefixes removed.
so just do not specify any name,
#implementation AbcModule
// To export a module named AbcModule
RCT_EXPORT_MODULE();
#end
in your case it should then be accessible from within JS with
AbcModule
But the documentation is not clear if the Objective-C Class declaration needs to be written with prefixed "RCT" or "RK".. but because both prefixes seem to be valid, you should be able to just use AbcModule without prefix.
In other words, if you want to use GetDetails from within JS you need to name your interface and implementation accordingly
#implementation RCTGetDetails
RCT_EXPORT_MODULE(GetDetails);
// or
// RCT_EXPORT_MODULE();
#end
Okay, if there is someone who is facing this issue and feels like their code should work but it isn't and any solution online not working for you as well.
Try this:
When you create your .h and .m file for header and objective-c or swift file, make sure you do it in Xcode and not from VSCode.
VSCode eventually doesn't adds you .h file in the required resources folder, i have wasted my 2 weeks trying to find out solution for it, but lastly, that was it, yes this is it.
in your .m file, let's say GetDetails is a class of NSObject .swift
you need:
#interface RCT_EXTERN_MODULE(WidgetManager, NSObject)
// method to export
RCT_EXTERN_METHOD(isAuthenticated: (BOOL *)isAuthenticated)
#end
in your GetDetails.swift:
#objc(GetDetails)
class GetDetails: NSObject {
#objc(isAuthenticated:)
func isAuthenticated(_ isAuthenticated: Bool) {
}
}

Objective-c class exposed via bridging header not visible from swift when archiving release

In my react native project, I try to expose a swift function to the javascript code. It works well in debug mode, but when trying to archiving I get a Use of undeclared type RCTEventEmitter error on my swift file.
The RCTEventEmitter is imported in my RNUtils.m file, and in the bridging header.
So I guess somewhere in the archiving, something fail with the bridging header, but I have no idea where.
If I ask for a non existing import, it will tell me that it can't compile the bridging header, so the file is taken into account during the build.
// Utils.m
#import "React/RCTBridgeModule.h"
#import "React/RCTConvert.h"
#import "React/RCTEventEmitter.h"
#interface RCT_EXTERN_REMAP_MODULE(RNUtils, RNUtils, RCTEventEmitter)
#end
// Utils.swift
import Foundation
#objc(RNUtils)
class RNUtils: RCTEventEmitter {
// my native code emitting events
}
// MyApp-Bridging-header.h
#ifndef MyApp_Bridging_Header_h
#define MyApp_Bridging_Header_h
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#endif
react-native 0.61.5
xcode 11.5
Swift 5
It appears I needed to add ìmport React` in every swift file. It's archiving fine now.

Swift framework - Use Swift class reference in Objective-C class

I am creating Swift framework in which I have to use Objective-C class. So I went through this link. This is the public header of my framework :
#import <UIKit/UIKit.h>
//! Project version number for Test.
FOUNDATION_EXPORT double TestVersionNumber;
//! Project version string for Test.
FOUNDATION_EXPORT const unsigned char TestVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Test/PublicHeader.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <sys/socket.h>
#import <MyTest/MPAppDelegateProxy.h>
Now in class MPAppDelegateProxy, I have to use a Swift class which I have created. This is :
#import "MPAppDelegateProxy.h"
#import "MyTest.h"
#implementation MPAppDelegateProxy
+ (void)proxyAppDelegate {
[MPGlobal MPLog:#"App delegate not set, unable to perform automatic setup." file:#"MPAppDelegateProxy.m" function:#"proxyAppDelegate" line:32];
// rest of code
}
MPGlobal is one of my Swift class. But I am getting :
Use of undeclared identifier 'MPGlobal'
Note : I have added #objC before MPGlobal.
You need to import <Target>-Swift.h file.
This is known as Objective-C Generated Interface Header Name.
You can find it in your Target's build settings.
This file is auto generated by compiler and it needs to be imported in Objective-C files.
change the SWIFT_OBJC_INTERFACE_HEADER_NAME build setting and making it the same across different targets. To do so change the instruction that generates this property from $(SWIFT_MODULE_NAME)-Swift.h to $(PROJECT_NAME)-Swift.h as explained here
After doing this Clean Build Folder by pressing Alt and going into Product menu. Since name of header is shared among targets now it can be imported once in the .m ObjectiveC file and all targets can benefit from Swift classes.
If after building it still shows the error, ensure that the header can be reached from XCode by Cmd clicking on its name. It should open a file that contains code similar to this:
SWIFT_CLASS("_TtC27ProjectName_Summary11MyClass")
#interface MyClass : NSObject
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
If need to ensure that those headers are being generated open a terminal and use this command
find ~/Library/Developer/Xcode/DerivedData -name "*Swift.h"
You should see one header for each target
Another issue that happened to me after those changes is that it started giving errors on ObjectiveC code that I didn't touch. The problem was due to the position of the import, as reported here:
Exactly where at the top of a .m file you #import the hidden bridging
header can make a difference. The usual sign of trouble is that you
get an “Unknown type name” compile error, where the unknown type is a
class declared in Objective-C. The solution is to #import the .h file
containing the declaration for the unknown type in your Objective-C
files as well, before you #import the hidden bridging header. Having
to do this can be an annoyance, especially if the Objective-C file in
question has no need to know about this class, but it resolves the
issue and allows compilation to proceed.
At the very end the code compiles and runs on device and simulator!
Original answer
Also you can try this,
You needed to import the -Swift.h for for both the framework and the app target
For Example :
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
#import "XLPagerTabStrip-Swift.h"
#import "RealmSwift-Swift.h"
...... // Add all frameworks, subclasses, and dependance ios frameworks
#import "MyProject-Swift.h"
You can read this article How to import file header and check paths

RCTBridge is Always Nil

I have been using React Native for a mobile app project for over a year now. I have a native component to bridge the BLE stack to the React Native portion of the app. Recently I upgraded to version 9.1 of XCode and I cannot get the React-Native Bridge to work within the iOS version. The RCTBridge is always nil so I can never use the eventDispatcher(). Here is my setup:
I have a native Swift component which I integrate into the app via a bridgin header. The origanization looks like this:
BLEScanner.swift (This is the native component)
BluetoothModuleBridge.m
Module-Practive-Bridging-Header.h (The bridging header)
Relevant code snippets from each file:
BLEScanner.swift
import Foundation
#objc(BLEScanner)
class BLEScanner: NSObject {
//....
var bridge: RCTBridge! // THIS IS ALWAYS NIL
//....
#objc func requestBluetoothState() -> Void {
print("REQUEST BLE STATE")
let ret = [
"enabled" : true
]
//THIS LINE WILL FAIL BECAUSE bridge IS NIL
self.bridge.eventDispatcher().sendDeviceEvent(withName: "BluetoothStateEvent", body: ret)
}
}
BluetoothModuleBridge.m
#import <React/RCTBridgeModule.h>
#interface RCT_EXTERN_MODULE(BLEScanner, NSObject)
RCT_EXTERN_METHOD(requestBluetoothState)
#end
Module-Practive-Bridging-Header.h
// BluetoothModule-Bridging-Header.h
#import <React/RCTBridge.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
#import <React/RCTConvert.h>
#import "AppDelegate.h"
#import "BugsnagReactNative/BugsnagReactNative.h"
#import "nokeLockSDK.h"
#import "nokeServerSDK.h"
#import "TI_aes_128.h"
What I have Tried
Updated React Native from 0.36 to 0.50.3
Tried running on multiple devices
Tried on older version of XCode
Tried compiling on different machine
Compared to a similar app that works and uses this same design.
I am very confused as to why the RCTBridge is returning as nil. It seems odd to me that an XCode update would cause this, however, it is the only change made.
Can anyone point me in the right direction in debugging this issue?
I am using XCode 9.1 and React Native 0.50.3
You do not have to subclass RCTEventEmitter. Just add the #objc attribute. So the variable should be #objc var bridge: RCTBridge!
Do you have your own initial method? If so try remove it. After my test, it has no problem.
And it is recommended to Subclass RCTEventEmitter instead.
If you upgraded to 9.1 and also React Native to 50.x from 30.x at the same time, you could have wrong imports, as that is something that changed around version 40.
It should be
#import <React/RCTBridgeModule.h>
If you don't want to subclass RCTEventEmitter, implement protocol RCTBridgeModule in your BLEScanner.
That will solve the problem.

#import ProjectName-Swift.h into header file Can't use swift as .h property?

So I'm trying to use an #objc swift class as a property on my objective-c header file.
example
#objc class SwiftClass: NSObject {
}
#interface ObjcObject : NSObject
#pragma mark - Public Properties -
#property (nonatomic, weak) SwiftClass* swiftClass;
However if I #import ProjectName-Swift.h it gives me the error that "'ProjectName-Swift.h'file not found'
I found an answer here that implies you can't actually import Swift into a header file https://stackoverflow.com/a/29951314/3877767
How then am I supposed to use swift code together with objc code? I would not call swift and objc interoperable if you can't use #objc marked swift classes as properties on and objc header file
So inside of my App-Bridging-Header.h
#import "ObjcClass.h"
and inside of my ObjcClass.h
#import "ProjectName-Swift.h"
This gives the error ProjectName-Swift.h can't find file
Either removing the #import ProjectName-Swift.h, or the #import ObjcClass.hfixes the problem, but then I can't use the Swift/OBJC code respectively
You don't import the header file. You give it to the compiler as a so-called "bridging header" that tells the compiler what to share between the two language environments.
You need to put your header file under the Objective-C Bridging Header as shown below:

Resources