Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send events from ViewController to React-Native

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

like image 876
Crystalii Avatar asked Aug 07 '26 09:08

Crystalii


1 Answers

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
  • RNEventEmitter.swift
  • MyViewController.swift (or any other class of yours)

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),
  );
like image 76
Crystalii Avatar answered Aug 09 '26 00:08

Crystalii



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!