发送事件从SWIFT或Objective-C的

问题描述:

我已经创建了下面的类(精简版),以JS,继承人参考完整的文件 https://github.com/cotyembry/CastRemoteNative/blob/7e74dbc56f037cc61241f6ece24a94d8c52abb32/root/ios/CastRemoteNative/NativeMethods.swift发送事件从SWIFT或Objective-C的

@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) 
    } 
} 

这完美的作品,并触发我的回调监听器是在我的javascript代码时,我调用emitEvent方法类似下面,它从 https://github.com/cotyembry/CastRemoteNative/blob/7e74dbc56f037cc61241f6ece24a94d8c52abb32/root/js/Components/ChromecastDevicesModal.js

改变片段从JavaScript端

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

//here I bring in the swift class to use inside javascript 
var NativeMethods = NativeModules.NativeMethods; 

//create an event emitter to use to listen for the native events when they occur 
this.eventEmitter = new NativeEventEmitter(NativeMethods); 
//listen for the event once it sends 
this.subscription = this.eventEmitter.addListener('test', (body) => { console.log('in test event listener callback', body)}); 

NativeMethods.sendEventToJSFromJS() //call the native method written in swift 

我只是有sendEventToJSFromJS方法调用上的按钮按下的JavaScript

同样,这个工作和console.log('in test event listener callback', body)代码工作和运行在JavaScript端

我的问题,即这不工作:

如果我定义的类后做迅速文件中的以下,这是行不通的:

var nativeMethodsInstance = nativeMethods() 
nativeMethodsInstance.sendEventToJSFromSwift() 

为什么?因为下面的错误被抛出:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'bridge is not set. This is probably because you've explicitly synthesized the bridge in NativeMethods, even though it's inherited from RCTEventEmitter.' 

因此,创建NativeMethods的instance时,对不......有什么区别?

有关其他信息:

Objective-C中得到相同的桥梁没有设置问题,当我写的代码,这些相同的片段中的.h和.m文件,而不是在.swift文件

我发现这里是越来越打印错误消息中的本地代码,但它只是具有可变

_bridge 

并且被检查以查看它是否是nil

的文件是这个错误来自是:

RCTEventEmitter.h 
RCTEventEmitter.c 

这里是RCTEventEmitter.c

- (void)sendEventWithName:(NSString *)eventName body:(id)body 
{ 


    RCTAssert(_bridge != nil, @"bridge is not set. This is probably because you've " 
     "explicitly synthesized the bridge in %@, even though it's inherited " 
     "from RCTEventEmitter.", [self class]); 

    if (RCT_DEBUG && ![[self supportedEvents] containsObject:eventName]) { 
    RCTLogError(@"`%@` is not a supported event type for %@. Supported events are: `%@`", 
       eventName, [self class], [[self supportedEvents] componentsJoinedByString:@"`, `"]); 
    } 
    if (_listenerCount > 0) { 
    [_bridge enqueueJSCall:@"RCTDeviceEventEmitter" 
        method:@"emit" 
         args:body ? @[eventName, body] : @[eventName] 
       completion:NULL]; 
    } else { 
    RCTLogWarn(@"Sending `%@` with no listeners registered.", eventName); 
    } 
} 

充分片断哪里该_bridge值被置以及它是怎样到达集,所以我可以知道,在它发生故障的情况下,如何设置

我发现下面还RCTEventEmitter.h

@property (nonatomic, weak) RCTBridge *bridge; 

在给出的错误中提到该桥是在RCTEventEmitter中继承的,所以这可能是weak部分与bridge属性的问题?

或者我需要改变我的策略,我如何在一起做这件事?

我知道它可能有要的东西都与我没有完全理解代码的

@synthesize bridge = _bridge; 

一部分,并在犯规帮助混合所有的语言多笑...

这真的很难,所以任何帮助将非常感谢! 非常感谢您的时间

这里是当项目历史码代表我上面的问题的代码整个项目的链接(因为我自做变更项目):

https://github.com/cotyembry/CastRemoteNative/tree/7e74dbc56f037cc61241f6ece24a94d8c52abb32

我想通了

警告:该解决方案采用的方法已过时反应native方法 - 我无法弄清楚如何“正确”,从RCTEventEmitter继承和发送事件前夕... RY时间我试图_bridge将结束是nil

确保斯威夫特桥接到目标C(如果你使用迅速发送事件的JavaScript)

创建的实例导出本机模块(无论它们是用Swift还是Objective C编写)

让React Native的底层实现可以做到这一点,并且对于需要发送事件的每个类,导出特定的Native Class Objective C代码或Swift代码(本机模块)为React-Native。这使得javascript才能够听取事件

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!!!") 
    } 
} 

AppDelegate.h放(附加到已经在文件中的代码)

#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 

AppDelegate.m放(除代码这是已经在文件中)

#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; 
} 

重要 - 也请务必添加如下:●代码到目标C的.h的牵线搭桥头,使这个PublicBridgeHelper定义可用INE在.swift代码

#import "AppDelegate.h" 

终于可以使用,

现在向您展示如何设置使用的rnBridgeFromRootView变量AppDelegate.m(即获取返回,右发送事件的JavaScript之前在.swift代码中使用)

开放AppDelegate.m并在

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... } 
方法体210

包括实例化rootView可变

即代码行后的以下这可能看起来像

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

添加行之后:

rnBridgeFromRootView = rootView.bridge //set the bridge to be exposed and returned later and used by the swift class 

我们解释publicBridgeHelperInstance.getBridge()一部分是在.swift文件

publicBridgeHelper是一个目标C类的一个实例,其允许快速类的能力得到反应本地桥的参考

如果你仍然有问题理解摹我的答案读这我做了一个视频过它,你可以在这里观看之后:

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

+0

为什么你会混合使用SWIFT代码一个Objective-C的appDelegate? –

+0

,因为我需要它将代码 –

+0

中的rootView.bridge(即网桥变量)@thibautnoah暴露给其他部分,您可以通过修改我在AppDelegate.m中使用的代码来使用.swift版本的应用程序委托,但从我记忆中,在Swift中,它用我们使用的方法来给我提供那种语言的问题,以便让我获得桥接(但是从我看过它已经有一段时间了) –