2016-03-18 51 views
6

我無法爲了我的生活而得到一個事件,以正確地從橋本身的iOS發送到反應本地JS上下文。在Objective-C方面,我希望有一個模塊可以輕鬆地在橋上發送事件。我把這種現象稱之爲類EventEmitter其定義如下:聆聽反應原生ios中的事件

// EventEmitter.h 

#import "RCTBridge.h" 
#import "RCTEventDispatcher.h" 

@interface EventEmitter : NSObject<RCTBridgeModule> 

    - (void)emitEvent:(NSString *) eventName withData:(id) eventData; 

@end 

和實現:

// EventEmitter.m 

#import "EventEmitter.h" 

@implementation EventEmitter 

    RCT_EXPORT_MODULE(); 

    @synthesize bridge = _bridge; 

    - (void)emitEvent:(NSString *) eventName withData:(id) eventData 
    { 
    NSLog(@"emitting %@ with data %@", eventName, [eventData description]); 
    [[_bridge eventDispatcher] sendDeviceEventWithName:eventName body:eventData]; 
    [[_bridge eventDispatcher] sendAppEventWithName:eventName body:eventData]; 
    } 

@end 

我同時使用sendDeviceEvent和sendAppEvent因爲我無法得到任何工作。

在事情的JS方面我註冊接收這些事件在我的模塊之一的全局命名空間(以便我知道事件訂閱將發生在事件發射之前)。我這樣註冊:

console.log('ADDING EVENT LISTENERS'); 
NativeAppEventEmitter.addListener('blah', test => console.log('TEST1', test)); 
DeviceEventEmitter.addListener('blah', test => console.log('TEST2', test)); 

在我的日誌報表,我得到以下:

2016-03-19 12:26:42.501 [trace][tid:com.facebook.React.JavaScript] ADDING EVENT LISTENERS 
2016-03-19 12:26:43.613 [name redacted][348:38737] emitting blah with data [data redacted] 

所以我可以告訴大家,我派出了一個應用程序事件,並與標籤等等,我的設備事件已經註冊了使用DeviceEventEmitter和NativeAppEventEmitter監聽blah事件,但我沒有在偵聽器中回調。

我在做什麼錯?謝謝閱讀!

+0

乍一看,這看起來OK。 DeviceEventEmitter公開在react-native.js中。看看AppState模塊,例如:https://github.com/facebook/react-native/blob/ad8a33586410c6f9048983f64f8f86e0715e73b8/Libraries/AppState/AppState.js 你可以嘗試的是找到第三方模塊,它發出事件和看看它的代碼:https://js.coach/ –

+0

感謝您的快速回復馬丁。我一直在尋找使用NativeAppEventEmitter或DeviceEventEmitter的例子,他們所做的一切似乎與我所擁有的相同。我唯一能想到的是,因爲我有EventEmitter作爲自己的類,所以我在做一個標準的alloc/init來獲取它的一個實例,然後才能訪問emitEvent方法。我只是按自己的條件分配它的事實會產生什麼影響? –

+0

通過[EventEmitter alloc] init]創建新的EventEmitter實例嗎?如果是這樣,你可以在emitEvent方法中調試_bridge的值嗎? – halilb

回答

2

我試着指派事件,似乎當你創建新的手動EventEmitter情況下,通過使用[EventEmitter alloc] init]

你應該讓反應本地創建實例bridge將不會被初始化。我檢查了本地組件,他們使用-(void)setBridge:(RCTBridge *)bridge方法來完成初始化工作。請查看RCTLinkingManager查看示例。它使用NSNotificationCenter來處理事件。

// registering for RCTOpenURLNotification evet when the module is initialised with a bridge 
- (void)setBridge:(RCTBridge *)bridge 
{ 
    _bridge = bridge; 

    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(handleOpenURLNotification:) 
               name:RCTOpenURLNotification 
              object:nil]; 
} 

// emitting openURL event to javascript 
- (void)handleOpenURLNotification:(NSNotification *)notification 
{ 
    [_bridge.eventDispatcher sendDeviceEventWithName:@"openURL" 
               body:notification.userInfo]; 
} 

// creating RCTOpenURLNotification event to invoke handleOpenURLNotification method 
+ (BOOL)application:(UIApplication *)application 
      openURL:(NSURL *)URL 
    sourceApplication:(NSString *)sourceApplication 
     annotation:(id)annotation 
{ 
    NSDictionary<NSString *, id> *payload = @{@"url": URL.absoluteString}; 
    [[NSNotificationCenter defaultCenter] postNotificationName:RCTOpenURLNotification 
                 object:self 
                userInfo:payload]; 
    return YES; 
} 
+0

這使我指出了正確的方向,謝謝! –

3

可以使用NativeEventEmitter

// register eventEmitter 
    const {NGListener} = NativeModules; // NSListener is my class 
    this.eventEmitter = new NativeEventEmitter(NativeModules.NGListener); 
    this.eventEmitter.addListener('CancelEvent', (data) => { 
     console.log(data); 
    }) 

在的ObjectiveC,您可以創建

#import <RCTViewManager.h> 
    #import <RCTEventEmitter.h> 
    @interface NGListener: RCTEventEmitter <RCTBridgeModule> 
    @end 

    @implementation NGListener 

    RCT_EXPORT_MODULE(); 

    - (NSArray<NSString*> *)supportedEvents { 
     return @[@"CancelEvent", @"OKEvent"]; 
    } 
    // And you sent event you want from objectC to react-native 
    [self sendEventWithName:@"CancelEvent" body:@"Tap`enter code here` on Cancel button  from Objc"]; 

我寫的樣本爲例,從處理的反應,原產於的ObjectiveC和對立事件。 https://github.com/lengocgiang/event-listener 希望這個幫助!

+0

每個'init'的順序是否重要? Obj-C部分的ReactNative部分? – Trip

1

在我的情況下,我通過保持RCTRootView的橋接值並將其傳遞給發射器實例來獲得此工作。

@implementation AppDelegate { 
    RCTBridge *rootBridge; 
} 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    NSURL *jsCodeLocation; 

    ...... 

    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 
                 moduleName:@"MyApp" 
               initialProperties:nil 
                launchOptions:launchOptions]; 
    rootBridge = rootView.bridge; 

    ....... 

} 

- (IBAction)doAction:(id)sender { 
    BridgeEvents *events = [[BridgeEvents alloc] init]; 
    [events setBridge:rootBridge]; 
    [events doMyAction]; 
} 

以我發射類別:

#import "RCTEventEmitter.h" 

@interface BridgeEvents : RCTEventEmitter <RCTBridgeModule> 
- (void)doMyAction; 
@end 

#import "BridgeEvents.h" 

@implementation BridgeEvents 

RCT_EXPORT_MODULE(); 

- (NSArray<NSString *> *)supportedEvents { 
    return @[@"onEvent"]; 
} 

- (void)doMyAction { 
    [self sendEventWithName:@"onEvent" body:@""]; 
} 

@end 
0

RNNotification *通知= [RNNotification allocWithZone:無]; [notification sendNotificationToReactNative]我嘗試了上面的所有內容,但無法在我的應用中使用它。

最後this爲我工作。

#import "RNNotification.h" 
@implementation RNNotification 

RCT_EXPORT_MODULE(); 

+ (id)allocWithZone:(NSZone *)zone { 
    static RNNotification *sharedInstance = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     sharedInstance = [super allocWithZone:zone]; 
    }); 
    return sharedInstance; 
} 

- (NSArray<NSString *> *)supportedEvents 
{ 
    return @[@"EventReminder"]; 
} 

- (void)sendNotificationToReactNative 
{ 
    [self sendEventWithName:@"EventReminder" body:@{@"name": @"name"}]; 
} 

同時INITING功能

RNNotification *notification = [RNNotification allocWithZone: nil]; 
[notification sendNotificationToReactNative]