I am a complete beginner when it comes to iOS programming. I have a React Native application, and I have made a native bridge to a Swift module. What I want to achieve is to be able to launch a native ViewController page from React Native, and then close the ViewController and send events containing data back to React Native.
I have edited in the following files:
Brygga.m (My ObjC bridge between React-Native and Swift)
Bridge-Test-Bridging-Header.h (Bridging-Header file)
ConnectingFile.swift (My Swift classes and methods)
I have the following files:
According to the tutorials I have read, to send events from native to React-Native, we have to use RCTEventEmitter. But I cannot initiate a ViewController from a RCTEventEmitter subclass, so I have made two classes.
One is a subclass of UIViewController, and one is subclass of RCTEventEmitter. I have successfully launched my ViewController, but when trying to send the event data from the ViewController back to React Native through my RCTEventEmitter class; I get the error
"Bridge is not set. This is probably because you've explicitly synthesized the bridge in Brygga, even though it's inherited from RCTEventEmitter."
ConnectingFile.swift
import Foundation
@objc(Connect)
class Connect: UIViewController, MiSnapWorkflowViewControllerDelegate{
func didFinishWithResults(resultsDictionary: [String : Any]) {
let event: brygga = Brygga()
brygga.Finished(data: "Hello")
}
@objc func startViewController() {
DispatchQueue.main.async {
let vc = MiSnapWorkflowViewController.init(with: [.passport, .selfie])
vc.delegate = self
let navigationController = UINavigationController(rootViewController: vc)
navigationController.modalPresentationStyle = .fullScreen
let topViewController = UIApplication.shared.keyWindow?.rootViewController
topViewController?.present(navigationController, animated: true, completion: nil)
}
}
}
@objc(Brygga)
class Brygga: RCTEventEmitter {
@objc
func Finished(data: String) {
sendEvent(withName: "onFinished", body: ["data": data])
}
override func supportedEvents() -> [String]! {
return ["onFinished"]
}
override static func requiresMainQueueSetup() -> Bool {
return true
}
}
Brygga.m
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#import <React/RCTViewManager.h>
@interface RCT_EXTERN_MODULE(Brygga, RCTEventEmitter)
RCT_EXTERN_METHOD(Finished)
@end
@interface RCT_EXTERN_MODULE(Connect, RCTViewManager)
RCT_EXTERN_METHOD(goToNative)
@end
BridgeTest-Bridging-Header.h
#import <React/RCTBridgeModule.h>
#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTEventEmitter.h>
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
#import <React/RCTConvert.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTViewManager.h>
I think it may have something to do with how I initiate the RCTEventEmitter class from my ViewController. This guy has a similiar problem but I couldn't understand the solution
Implement RCTEventEmitter in Swift but receive exception for bridge is not set
I eventually solved it. Here is the solution for sending events from your other classes that do not extend RCTEventEmitter, for instance if you like me want to send events from a class of yours that extends a UIViewController.
Your Swift bridge should consist of the following:
Bridge.m
@interface RCT_EXTERN_MODULE(RNEventEmitter, RCTEventEmitter)
RCT_EXTERN_METHOD(supportedEvents)
@end
RNEventEmitter.swift
@objc(RNEventEmitter)
open class RNEventEmitter: RCTEventEmitter {
public static var emitter: RCTEventEmitter!
override init() {
super.init()
RNEventEmitter.emitter = self
}
open override func supportedEvents() -> [String] {
["onFinished", "onPending"] // etc.
}
}
MyViewController.swift
func sendEvent(_ name: String, body: [String : Any]) {
RNEventEmitter.emitter.sendEvent(withName: name, body: body)
}
Then from just anywhere sendEvent("onFinished", "Native process has finished!")
Of course you will need to receive this on the React Native side as well. I can as well show how you can do that;
App.js
import {NativeModules, NativeEventEmitter} from 'react-native';
const {RNEventEmitter} = NativeModules;
const eventEmitter = new NativeEventEmitter(RNEventEmitter);
eventEmitter.addListener('onFinished', res =>
console.log(res.data),
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With