Quantcast
Channel: Active questions tagged react-native+typescript - Stack Overflow
Viewing all articles
Browse latest Browse all 6287

React Native: How can I send events from iOS (Swift) back to JavaScript?

$
0
0

I am working on a project where I want to integrate React-Native into a native Swift app. To make sure both sides are aware of state, I've made a 'message bus', A mechanism through which events can be passed from Javascript to native, and vice versa.

This works like a charm when sending an event from JS to iOS; it gets received, parsed and my Swift code knows exactly what to do. Sending an event from Swift to Javascript seems a lot harder - and poorly documented - as I find myself stuck on an error:

terminating with uncaught exception of type NSException*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error when sending event: RCTCrossPlatformEventBus.Event with body: {   "name" : "Authenticated",   "data" : "{\"firstName\":\"1\",\"email\":\"34\",\"lastName\":\"2\",\"password\":\"3\"}" }. RCTCallableJSModules is not set. This is probably because you've explicitly synthesized the RCTCallableJSModules in RCTEventEmitter, even though it's inherited from RCTEventEmitter.'

This error seems to be common as there are a lot of stack overflow questions and GitHub issues to be found on it. However, nearly all of them date back from ±5 years ago, and simply don't help me with my issue any more. Below, I'm listing my implementation. If anybody could provide me with some guidance on how to solve this issue, it would be highly appreciated.

RCTCrossPlatformEventBus.m

#import <Foundation/Foundation.h>#import "React/RCTBridgeModule.h"#import "React/RCTEventEmitter.h"@interface RCT_EXTERN_MODULE(RCTCrossPlatformEventBus, RCTEventEmitter)    RCT_EXTERN_METHOD(supportedEvents)    RCT_EXTERN_METHOD(processHybridEvent: (NSString *)name) // this receives JS events@end

RCTCrossPlatformEventBus.swift

@objc(RCTCrossPlatformEventBus)open class RCTCrossPlatformEventBus: RCTEventEmitter {    override init() {        super.init()    }    static let appShared = RCTCrossPlatformEventBus()    @objc    public override static func requiresMainQueueSetup() -> Bool {        return true    }    /// Processes a received event received from hybrid code    /// - Parameters:    ///   - json: the json encoded string that was sent    @objc func processHybridEvent(_ json: String) {        print("Swift Native processing event: \(json)")        DispatchQueue.main.async {            var jsonObject: [String: Any]?            if let jsonData = json.data(using: .utf8), let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as? [String:Any] {                jsonObject = dict            }            NotificationCenter.default.post(name: .RCTCrossPlatformEventBusEvent, object: self, userInfo: jsonObject)        }    }    /// Posts an event to both the hybrid code    /// - Parameters:    ///   - json: the json encoded string that will be sent    @objc func postEvent(json: String) {        self.sendEvent(withName: "RCTCrossPlatformEventBus.Event", body: json)    }    open override func supportedEvents() -> [String]! {        return ["RCTCrossPlatformEventBus.Event"]    }    open override func constantsToExport() -> [AnyHashable : Any]! {        return [:]      }}

App_Bridging_Header.h

#ifndef ArchitectureDemo_Bridging_Header_h#define ArchitectureDemo_Bridging_Header_h#import "React/RCTBridgeModule.h"#import "React/RCTEventEmitter.h"#import "RCTCrossPlatformEventBus.m"

Then, in Javascript (Typescript actually)

import { NativeModules, NativeEventEmitter } from 'react-native'import { BehaviorSubject, Observable } from 'rxjs'const { CrossPlatformEventBus } = NativeModules;const eventEmitter = new NativeEventEmitter(CrossPlatformEventBus)class RNCrossPlatformEventBus {    // we set up a private pipeline for events we can post to    private postableEventBus = new BehaviorSubject<string>('')    // and then expose it's observable for everyone to subscribe to    eventBus = this.postableEventBus.asObservable()    constructor() {        eventEmitter.addListener('RCTCrossPlatformEventBus.Event', (body) => {            this.processEventFromNative(body)        })    }    postEvent(json: string) {        this.postableEventBus.next(json)        CrossPlatformEventBus.processHybridEvent(json);    }    processEventFromNative(jsonString: string) {        this.postableEventBus.next(jsonString)        console.log(`React-Native received event from native ${jsonString}`)    }}export default new RNCrossPlatformEventBus()

Viewing all articles
Browse latest Browse all 6287

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>