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!
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.
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.
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.
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;
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
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]
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