Listening for events in react native ios

I've tried dispatching events and it seems bridge is not initialised when you create new EventEmitter instances manually by using [EventEmitter alloc] init]

You should let react-native create instances. I checked native components and they're using -(void)setBridge:(RCTBridge *)bridge method to do initialisation work. Please check out RCTLinkingManager to see an example. It's using NSNotificationCenter to handle events.

// registering for RCTOpenURLNotification evet when the module is initialised with a bridge
- (void)setBridge:(RCTBridge *)bridge
{
  _bridge = bridge;

  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(handleOpenURLNotification:)
                                               name:RCTOpenURLNotification
                                             object:nil];
}

// emitting openURL event to javascript
- (void)handleOpenURLNotification:(NSNotification *)notification
{
  [_bridge.eventDispatcher sendDeviceEventWithName:@"openURL"
                                              body:notification.userInfo];
}

// creating RCTOpenURLNotification event to invoke handleOpenURLNotification method
+ (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)URL
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation
{
  NSDictionary<NSString *, id> *payload = @{@"url": URL.absoluteString};
  [[NSNotificationCenter defaultCenter] postNotificationName:RCTOpenURLNotification
                                                      object:self
                                                    userInfo:payload];
  return YES;
}

You can using NativeEventEmitter

// register eventEmitter
    const {NGListener} = NativeModules; // NSListener is my class
    this.eventEmitter = new NativeEventEmitter(NativeModules.NGListener);   
    this.eventEmitter.addListener('CancelEvent', (data) => {
      console.log(data);
    })

In ObjectiveC , you can create

    #import <RCTViewManager.h>
    #import <RCTEventEmitter.h>
    @interface NGListener: RCTEventEmitter <RCTBridgeModule>
    @end

    @implementation NGListener

    RCT_EXPORT_MODULE();

    - (NSArray<NSString*> *)supportedEvents {
        return @[@"CancelEvent", @"OKEvent"];
    }
    // And you sent event you want from objectC to react-native
    [self sendEventWithName:@"CancelEvent" body:@"Tap`enter code here` on Cancel button      from Objc"];

I wrote sample example to handle event from react-native to objectivec and opposite. https://github.com/lengocgiang/event-listener Hope this help!!


In my case I got this working by keeping a value of the bridge from RCTRootView and passing it to the Emitter Instance.

@implementation AppDelegate {
  RCTBridge *rootBridge;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSURL *jsCodeLocation;

  ......

  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"MyApp"
                                               initialProperties:nil
                                                   launchOptions:launchOptions];
  rootBridge = rootView.bridge;

  .......

}

- (IBAction)doAction:(id)sender {
  BridgeEvents *events = [[BridgeEvents alloc] init];
  [events setBridge:rootBridge];
  [events doMyAction];
}

In my Emitter Class:

#import "RCTEventEmitter.h"

@interface BridgeEvents : RCTEventEmitter <RCTBridgeModule>
- (void)doMyAction;
@end

#import "BridgeEvents.h"

@implementation BridgeEvents

RCT_EXPORT_MODULE();

- (NSArray<NSString *> *)supportedEvents {
  return @[@"onEvent"];
}

- (void)doMyAction {
  [self sendEventWithName:@"onEvent" body:@""];
}

@end