Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Listening for events in react native ios

I cannot for the life of me get an event to properly send from iOS native across the bridge to the react native JS context. On the Objective-C side I want to have a module to easily send events across the bridge. I have called this class EventEmitter and its definition is as follows:

// EventEmitter.h

#import "RCTBridge.h"
#import "RCTEventDispatcher.h"

@interface EventEmitter : NSObject<RCTBridgeModule>

  - (void)emitEvent:(NSString *) eventName withData:(id) eventData;

@end

and the implementation:

// EventEmitter.m

#import "EventEmitter.h"

@implementation EventEmitter

  RCT_EXPORT_MODULE();

  @synthesize bridge = _bridge;

  - (void)emitEvent:(NSString *) eventName withData:(id) eventData
  {
    NSLog( @"emitting %@ with data %@", eventName, [eventData description] );
    [[_bridge eventDispatcher] sendDeviceEventWithName:eventName body:eventData];
    [[_bridge eventDispatcher] sendAppEventWithName:eventName body:eventData];
  }

@end

I'm using both sendDeviceEvent and sendAppEvent because I can't get either to work.

On the JS side of things I register to receive these events in the global namespace of one of my modules (so that I know the event subscription will happen before the event is emitted). I register like this:

console.log( 'ADDING EVENT LISTENERS' );
NativeAppEventEmitter.addListener( 'blah', test => console.log( 'TEST1', test ) );
DeviceEventEmitter.addListener( 'blah', test => console.log( 'TEST2', test ) );

In my log statements I get the following:

2016-03-19 12:26:42.501 [trace][tid:com.facebook.React.JavaScript] ADDING EVENT LISTENERS
2016-03-19 12:26:43.613 [name redacted][348:38737] emitting blah with data [data redacted]

So I can tell that I am sending both an app event and a device event with the tag blah and I have registered to listen for the blah event with both the DeviceEventEmitter and NativeAppEventEmitters but I'm not getting called back in the listeners.

What am I doing wrong?? Thanks for reading!

like image 613
Jacob Patenaude Avatar asked Mar 18 '16 19:03

Jacob Patenaude


People also ask

What is event listener in React Native?

Event Listener is an important part of JavaScript where UI responds according to an event that occurs. Event listeners wait for an event to occur and pass that event across different files. It helps us to add interactive functionality to our react native app by listening to the events. Let’s see an example of Event Listener in React Native hooks.

What is React Native and how does it work?

React Native is a programming framework that uses a universal programming language called JavaScript. React Native gives developers the ability to develop full, native mobile applications for both Android and iOS. The main benefit of applying React Native is that developers won’t have to build the same Android and iOS.

How to integrate React-Native-calendar-events with native code?

Install the react-native-calendar-events library with native code. Step 2. - Link the library Since this package contains native code, you will need to include the code as a library. The React Native documentation on "Linking Libraries" also provides some details for this process.

How to access the Calendar module in React-Native?

In order to access your native module from JavaScript you need to first import NativeNodules from React Native: import { NativeModules } from 'react-native'; You can then access the CalendarModule native module off of NativeModules. const { CalendarModule } = NativeModules;


4 Answers

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;
}
like image 135
halilb Avatar answered Oct 10 '22 22:10

halilb


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!!

like image 43
Giang Avatar answered Oct 11 '22 00:10

Giang


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
like image 2
John Paul Manoza Avatar answered Oct 11 '22 00:10

John Paul Manoza


RNNotification *notification = [RNNotification allocWithZone: nil]; [notification sendNotificationToReactNative]I tried everything above and was not able to get it work in my app.

Finally this worked for me.

#import "RNNotification.h"
@implementation RNNotification

RCT_EXPORT_MODULE();

+ (id)allocWithZone:(NSZone *)zone {
    static RNNotification *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [super allocWithZone:zone];
    });
    return sharedInstance;
}

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

- (void)sendNotificationToReactNative
{
    [self sendEventWithName:@"EventReminder" body:@{@"name": @"name"}];
}

and while initing the function

RNNotification *notification = [RNNotification allocWithZone: nil];
[notification sendNotificationToReactNative]
like image 1
Niranjan Molkeri Avatar answered Oct 10 '22 23:10

Niranjan Molkeri