Passing events from Swift or Objective-C to JavaScript is a seamless process

A custom class was created with the following condensed version provided. For a reference to the full file, please visit this link.

@objc(NativeMethods)
class NativeMethods: RCTEventEmitter {
  @objc(sendEventToJSFromJS)
  func sendEventToJSFromJS {
    self.emitEvent(eventName: "test", body: "bodyTestString")
  }
  func emitEvent(eventName: String: body: Any) {
    self.sendEvent(withName: eventName, body: body)
  }
}

The functionality works smoothly and triggers the callback listener in my JavaScript code when the emitEvent method is called. This adjusted snippet from here demonstrates how it's done.

In the JavaScript segment:

import {
  NativeModules,
  NativeEventEmitter
} from 'react-native'

var NativeMethods = NativeModules.NativeMethods;

this.eventEmitter = new NativeEventEmitter(NativeMethods);
this.subscription = this.eventEmitter.addListener('test', (body) => { console.log('in test event listener callback', body)});

NativeMethods.sendEventToJSFromJS()

The button press invokes the sendEventToJSFromJS method in JavaScript successfully.

However, the issue arises if attempting to call the sendEventToJSFromSwift() method in the Swift file after defining the class:

var nativeMethodsInstance = nativeMethods()
nativeMethodsInstance.sendEventToJSFromSwift()

This action results in an error stating: 'Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'bridge is not set. [...]''

A deeper look into the code reveals that the bridge value needs to be properly set for the operation to succeed. The question remains - where and how should this bridge value be set?

Any insights or guidance on resolving this challenge would be greatly appreciated. Thank you for taking the time to assist!

You can access the complete project here, representing the code mentioned above.

Answer №1

I have successfully resolved the issue

Caution: Please be advised that this solution involves using a deprecated method in react native implementation. I encountered difficulties trying to inherit from RCTEventEmitter and send an event as intended, resulting in the _bridge variable becoming nil every time.

Make sure Swift is properly connected to Objective C (in case you're utilizing swift for sending events to JavaScript)

Do not create instances of exported Native modules (whether written in Swift or Objective C)

Instead, let React Native's underlying structure handle this by exporting specific Native Class Objective C Implementation code or Swift code (the Native Module) to React-Native for each class that needs to send an event. This setup allows JavaScript to listen for the event.

var publicBridgeHelperInstance = PublicBridgeHelper()  //create an instance of the objective c class inside the .swift file for future use in obtaining a reference to the bridge required for sending events to JavaScript 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) {
    //assume this deviceDidComeOnline function is triggered independent of javascript, possibly from native code or even a native button click to verify functionality...

    //emit an event to a javascript function within a React Native Component listening for the event like so:

    //1. obtain the bridge reference to facilitate event transmission from Native to Javascript in React Native (custom code involved here to make this operation functional)
    let rnBridge = publicBridgeHelperInstance.getBridge()  //fetches the bridge stored in AppDelegate.m via the `rootView.bridge` attribute (details on this below)

    //(if needed, confirm bridge availability with a print statement:
    print("rnBridge = \(rnBridge)")

    //2. actually dispatch the event through the eventDispatcher
    rnBridge?.eventDispatcher().sendAppEvent(withName: "test", body: "testBody data!!!")
  }
}

In AppDelegate.h, add (in addition to existing code present in the file)

#import "YourProjectsBridgingHeaderToMakeThisCodeAvailableInSwift.h"  //replace this with your actual header created when integrating a swift file (refer to guides if unsure how to connect swift to objective c)

@interface PublicBridgeHelper: NSObject
  -(RCTBridge*)getBridge;
@end

In AppDelegate.m, include (alongside existing content in the file)

#import <React/RCTRootView.h>

RCTBridge *rnBridgeFromRootView;

@implementation PublicBridgeHelper    //established solely to return rnBridgeFromRootView defined above to my Swift class while sending an event to JavaScript within a react native Component
-(RCTBridge*)getBridge {
  NSLog(@"rnBridgeFromRootView = @%@", rnBridgeFromRootView);
  return rnBridgeFromRootView;
}

Note: Ensure to append the following line of code to the bridging header file in Objective C .h to enable usage of the PublicBridgeHelper definition in the .swift code

#import "AppDelegate.h"

lastly,

To illustrate setting up the rnBridgeFromRootView variable utilized in AppDelegate.m (later returned and used in the .swift code before transmitting the event to javascript)

Go into AppDelegate.m and within the method body of

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... }

Add the following after the line that initializes the rootView variable

e.g., following a line resembling

RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"YourProjecNameProbably" initialProperties:nil launchOptions: launchOptions];

insert:

rnBridgeFromRootView = rootView.bridge  //set the bridge to be exposed, retrieved later, and utilized by the swift class

Explaining the

publicBridgeHelperInstance.getBridge()
segment found in the .swift file

publicBridgeHelper denotes an instance of an objective c class granting the swift class access to the react native bridge reference

If there are lingering issues comprehending my response, refer to my explanatory video for additional guidance:

https://www.youtube.com/watch?v=GZj-Vm9cQIg&t=9s

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Incorporate VLC player into a webpage without any visible control options

Is there a way to embed a flash video in a webpage without showing any controls? I managed to embed a flash video using VLC with the following code: <embed src="img/Wildlife.wmv" height="480" width="640"> However, I want the video to play without ...

Bootstrap modal fails to appear on screen

Using PHP, I generate a link from the controller. The link is stored in $retailer["url"] as 0125myimage.jpg <a onClick="crop('.$retailer["url"].')" data-target="#styledModal3" href="#" class="fa fa-edit lupa"></a> Here is my JavaSc ...

Access the child scope's attribute within the parent scope in AngularJS

angular.module('myApp',[]) .controller('Parent',['$scope',function($scope){ //no specific definition }]).controller('Child',['$scope',function($scope){ $scope.user={name:''}; //create a us ...

Adding to an existing array in MongoJS

I have been attempting to append data to an existing array in my mongoDB. The code snippet below is what I currently have, but unfortunately, it does not work as expected since all the existing data gets wiped out when I try to add new data: db.ca ...

Discover the magic of Material UI's Multiple Select feature for working with arrays

Utilizing the material-ui multiple select feature, I have set up a demo following the guidelines provided in the Multiple Select documentation. You can check out my example here: codesandbox In my demonstration, I am aiming to use 2 arrays for two separa ...

Attribute specified does not belong to type 'DetailedHTMLProps<ButtonHTMLAttributes

I am working on creating a reusable 'button' component and I would like to include a href attribute so that when the button is clicked, it navigates to another page. An Issue Occurred: The following error was encountered: 'The type '{ ...

"Encountering an issue with TestCafe's Selector - usage of the .find()

I've been having difficulty defining a selector in TestCafe using the ".find" method. My goal is to click on the link "Start a claim" as shown in the image below: https://i.sstatic.net/2BIRK.png Even though I'm using the id element and trying to ...

What is the method to disable response validation for image endpoints in Swagger API?

I'm working with a Swagger YAML function that looks like this: /acitem/image: x-swagger-router-controller: image_send get: description: Returns 'image' to the caller operationId: imageSend parameters: ...

Manipulating prop values through dropdown selection

I'm currently working on implementing filtering based on a prop value that changes according to the dropdown selection. Here's my progress so far: template(v-for="field in tableFields") th(:id="field.name") select(@change="filterScope(sc ...

How to clear a particular select option in react-bootstrap

I am looking for a solution to clear the second select when the first one selects option B. The clearing should involve removing the value, disabling it, and setting the default option to Select.... import React, { useState } from "react"; import ...

Tips for concealing an input IP Address in React

Looking for suggestions on an IP Address mask input solution. The format might vary between 999.99.999.99 and 99.9.99.9, but react-input-mask does not support varying lengths. Any recommendations? ...

The expect.objectContaining() function in Jest does not work properly when used in expect.toHaveBeenCalled()

Currently, I am working on writing a test to validate code that interacts with AWS DynamoDB using aws-sdk. Despite following a similar scenario outlined in the official documentation (https://jestjs.io/docs/en/expect#expectobjectcontainingobject), my asser ...

What is the process for modifying information within a text document?

What I am trying to achieve is a ticker with two buttons that can increment or decrement the value by one each time they are clicked. In addition, I want this value to be synced with a number stored in a text file. For instance, if both the counter and t ...

I possess an array containing objects of different lengths depending on the chosen city. How can I pinpoint the element that contains an object with a specific property?

My dilemma arises from the fact that the length of an array depends on the selected city, making it impossible to select elements using an index. In this scenario, I need to devise a method to choose elements based on the value of one of their properties. ...

Creating a table and populating its cells with values all within the confines of a single function

This section of code aims to create 3 arrays by extracting values inputted by the user from a popup menu in the HTML file. These values are then utilized to populate the table displayed below. var arrM = new Array; var arrT = new Array; var ar ...

In the world of Node.js and Java, the concepts of "if"

Here is a code snippet that I am working with: var randFriend = friendList[Math.floor(Math.random() * friendList.length)]; if (randFriend == admin) { //Do something here } else if (randFriend != admin) { client.removeFriend(randFriend); } I am tr ...

The return value cannot be retrieved from a promise function in Node

I'm facing an issue where the return value of a certain function is being executed before the actual result is returned. Can anyone provide guidance on how to solve this? Thanks! exports.addUser = async (data) => { const updateduser = await db.U ...

What is the best way to immediately update the state in a React functional component?

Having recently started learning React, I find myself struggling to understand the lifecycle of a functional component. Let's consider a scenario where I have multiple checkboxes labeled as: checkbox, a, b, c, and d, each corresponding to values a, b, ...

Retrieve various URLs within an object using React

My task involves extracting all URLs from a specific object. Object { "Info": "/api/2", "Logo": "/api/2/Logo", "Photo": "/api/2/photo", } I aim to store the responses in a state, ensuring t ...

Error: The "render" method is not available for the IncomingMessage object

While working on a basic application using node.js and express, everything seems to be in order except for this error that keeps popping up: res.render("aggregatedCostList",{ ^ TypeError: Object #<IncomingMessage> has no method 'render&ap ...