Send event to js from swift or objective-c
I figured it out
Warning: this solution uses a deprecated method react native method - I could not figure out how to "properly" inherit from the RCTEventEmitter
and send an event... every time I tried to the _bridge
would end up being nil
Make sure Swift is bridged to Objective C (if you're using swift to send the event to javascript)
Do Not create instances of the exported Native modules (whether they be written in Swift or Objective C)
Let React Native's underlying implementation do this and for each and every class that needs to send an event, export that particular Native Class Objective C Implementation code or Swift code (the Native Module) to React-Native. This allows the javascript to be able to listen to the event
var publicBridgeHelperInstance = PublicBridgeHelper() //instantiate the the objective c class from inside the .swift file to use later when needing to get a reference to the bridge to send an event to javascript written in react native
@objc(DeviceManager) //export swift module to objective c
class DeviceManager: NSObject {
@objc(deviceDidComeOnline:) //expose the function to objective c
public func deviceDidComeOnline(_ device: GCKDevice) {
//imagine this deviceDidComeOnline function gets called from something from the Native code (totally independent of javascript) - honestly this could be called from a native button click as well just to test it works...
//emit an event to a javascript function that is a in react native Component listening for the event like so:
//1. get a reference to the bridge to send an event through from Native to Javascript in React Native (here is where my custom code comes in to get this to actually work)
let rnBridge = publicBridgeHelperInstance.getBridge() //this gets the bridge that is stored in the AppDelegate.m file that was set from the `rootView.bridge` variable (more on this later)
//(if you want to print the bridge here to make sure it is not `nil` go ahead:
print("rnBridge = \(rnBridge)")
//2. actually send the event through the eventDispatcher
rnBridge?.eventDispatcher().sendAppEvent(withName: "test", body: "testBody data!!!")
}
}
in AppDelegate.h
put (additionally to the code that was already in the file)
#import "YourProjectsBridgingHeaderToMakeThisCodeAvailableInSwift.h" //replace this with your actual header you created when creating a swift file (google it if you dont know how to bridge swift to objective c)
@interface PublicBridgeHelper: NSObject
-(RCTBridge*)getBridge;
@end
in AppDelegate.m
put (in addition to the code that was already in the file)
#import <React/RCTRootView.h>
RCTBridge *rnBridgeFromRootView;
@implementation PublicBridgeHelper //this is created to SIMPLY return rnBridgeFromRootView defined above over to my Swift class when actually sending the event to javascript that defines a react native Component
-(RCTBridge*)getBridge {
NSLog(@"rnBridgeFromRootView = @%@", rnBridgeFromRootView);
return rnBridgeFromRootView;
}
important - also make sure to add the following line of code to the Objective C .h's bridging header to make this PublicBridgeHelper
definition available to be used in the .swift code
#import "AppDelegate.h"
finally,
now to show you how to set the rnBridgeFromRootView variable used in AppDelegate.m (that gets returned and used in the .swift code right before sending the event to javascript)
open AppDelegate.m
and in the method body of
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... }
include the following after the line of code that instantiates the rootView
variable
i.e. after the line that probably looks like
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"YourProjecNameProbably" initialProperties:nil launchOptions:launchOptions];
add:
rnBridgeFromRootView = rootView.bridge //set the bridge to be exposed and returned later and used by the swift class
Now to explain the publicBridgeHelperInstance.getBridge()
part that is in the .swift file
publicBridgeHelper
is an instance of an objective c class which allows the swift class ability to get a reference to the react native bridge
If you are still having problems understanding my answer after reading this I made a video over it and you can watch it here:
https://www.youtube.com/watch?v=GZj-Vm9cQIg&t=9s
React Native - Sending events from Native to JavaScript in AppDelegate (iOS)
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).
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;
}
Related Topics
Where to Get Frame Size of Custom Uiview in Its Subclass
Reading from the Clipboard with Swift 3 on MACos
"Nsurl" Is Not Implicitly Convertible to "Url"; Did You Mean to Use "As" to Explicitly Convert
How to Perform a Curl Request in Swift
Stop Objects from Colliding Using Spritekit
Difference Between Packed VS Normal Data Type
How to Set Inputview for Textfield in Swiftui
How to Get the Download Progress with the New Try Await Urlsession.Shared.Download(...)
Case Insensitive Dictionary in Swift
How to Check If a String Contains Chinese in Swift
Swiftui - How to Use Oncommand with Nsmenuitem on MACos
Swiftui: Dismiss View Within MACos Navigationview
How to Filter Events Created for the Current Date in the Realm Swift
Can't Create an Array of Types Conforming to a Protocol in Swift
Wcsession Has Not Been Activated
Swift: How to Fully Strip Internal/Inline Symbols
Swift: Uicollectionview Selecting Cell Indexpath Issues
How to Get the Yaw, Pitch, Roll of an Aranchor in Absolute Terms