[英]React Native: How can I send events from iOS (Swift) back to JavaScript?
I am working on a project where I want to integrate React-Native into a native Swift app.我正在做一个项目,我想将 React-Native 集成到本机 Swift 应用程序中。 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.
为了确保双方都知道 state,我制作了“消息总线”,这是一种可以将事件从 Javascript 传递到本地的机制,反之亦然。
This works like a charm when sending an event from JS to iOS;当从 JS 向 iOS 发送事件时,这就像一个魅力; it gets received, parsed and my Swift code knows exactly what to do.
它被接收、解析并且我的 Swift 代码确切地知道该怎么做。 Sending an event from Swift to Javascript seems a lot harder - and poorly documented - as I find myself stuck on an error:
将事件从 Swift 发送到 Javascript 似乎要困难得多——而且记录不充分——因为我发现自己陷入了一个错误:
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.这个错误似乎很常见,因为上面有很多堆栈溢出问题和 GitHub 问题。 However, nearly all of them date back from ±5 years ago, and simply don't help me with my issue any more.
但是,几乎所有这些都可以追溯到 ±5 年前,并且不再帮助我解决我的问题。 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 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 RCTC跨平台事件总线.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 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)然后,在 Javascript (实际上是打字稿)
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()
I resolved my problem in the meantime and am posting the answer here for future reference.我同时解决了我的问题,并在此处发布答案以供将来参考。
As it turns out, initializing my RCTCrossPlatformEventBus
- as I do in my swift file - Is an invalid operation.事实证明,初始化我的
RCTCrossPlatformEventBus
- 就像我在 swift 文件中所做的那样 - 是一个无效操作。 React-Native already initialize this, so rather than creating a singleton myself, I just had to override it's initializer like so: React-Native 已经初始化了它,所以我不必自己创建 singleton ,我只需要像这样覆盖它的初始化程序:
open class RCTCrossPlatformEventBus: RCTEventEmitter {
public static var shared: RCTCrossPlatformEventBus?
override init() {
super.init()
RCTCrossPlatformEventBus.shared = self
}
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.