2017-04-06 52 views
5

我已經創建了下面的類(精簡版),以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

回答

1

我想通了

警告:該解決方案採用的方法已過時反應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中,它用我們使用的方法來給我提供那種語言的問題,以便讓我獲得橋接(但是從我看過它已經有一段時間了) –