Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native - Sending events from Native to JavaScript in AppDelegate (iOS)

In my React native app, I am trying to send events from Native Code to JavaScript in the AppDelegate. To do this I call:

[self.bridge.eventDispatcher sendAppEventWithName:@"EventReminder"
                                           body:@{@"name": eventName}];

In my app delegate. Of course to do this I need to import:

import "RCTBridge.h"

import "RCTEventDispatcher.h"

and synthesize the bridge

@synthesize bridge = _bridge;

But event after this, the bridge variable doesn't exist. To make this error go away I made my AppDelegate conform to the RCTBridgeModule protocol like so:

AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeModule>

And then in my AppDelegate.m, I did:

RCT_EXPORT_MODULE()

After all that my bridge is finally not erroring, but Everytime I use it in the AppDelegate, it is nil.

Where am I going wrong?

Thanks in advance.

like image 666
coldbuffet Avatar asked Feb 04 '16 04:02

coldbuffet


2 Answers

RCTBridge creates new instances of each module class when it starts up, so when you export your AppDelegate as a bridge module, you're telling the bridge to create a new AppDelegate, and give it a bridge instance.

iOS also creates an instance of AppDelegate when your application launches, but the instance created by iOS isn't the same instance created by RCTBridge.

So basically, you have two instances of AppDelegate: the one you're trying to access self.bridge from, which wasn't created by RCTBridge and so doesn't have a reference to it, and the one created by RCTBridge, which has a bridge, but isn't the delegate for your UIApplication, and isn't running your code.

You have a few options:

1) you could pass your AppDelegate instance into the bridge when you create it by using the RCTBridgeDelegate's extraModules method. This lets you tell the bridge to use an existing instance of a module, instead pf creating a new one.

2) you could access the bridge via your RCTRootView instead of making your AppDelegate into a module so that it gets given a self.bridge property.

3) Move the logic that needs to talk to the bridge out of AppDelegate into a new module. If it needs to be triggered by an event inside AppDelegate, use NSNotifications to communicate with the module instance (we use this pattern for RCTPushNotificationManager).

Of these options,

Option 1) is probably the most complicated to do correctly.

Option 2) is probably the easiest to do because you presumably already have an instance of RCTRootView in your AppDelegate that you can reference.

Option 3) is ideal from a technical perspective, because it prevents you from accidentally sending events before the bridge is properly initialized (which might crash, or behave unexpectedly).

like image 173
Nick Lockwood Avatar answered Sep 22 '22 07:09

Nick Lockwood


Alternatively you can use NSNotificationCenter.

For example to process incoming push notifications in AppDelegate

didReceiveRemoteNotification:

post a NSNotification. Observe this NSNotification by name in a subclass of RCTEventEmitter. Then call

[self sendEventWithName:@"eventName" body:eventBody];

in the respective selector.

See: Send and receive messages through NSNotificationCenter in Objective-C?

like image 30
Saurabh Davala Avatar answered Sep 20 '22 07:09

Saurabh Davala