2016-03-18 25 views
6

Non riesco a ottenere correttamente un evento per l'invio da un nativo iOS attraverso il bridge al contesto JS nativo reattivo. Sul lato Objective-C voglio avere un modulo per inviare facilmente eventi attraverso il bridge. Ho chiamato questa classe EventEmitter e la sua definizione è la seguente:Ascolto per eventi in risposta ios nativo

// EventEmitter.h 

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

@interface EventEmitter : NSObject<RCTBridgeModule> 

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

@end 

e l'implementazione:

// 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 

sto utilizzando sia sendDeviceEvent e sendAppEvent perché non riesco neanche a lavorare.

Sul lato JS delle cose mi registro per ricevere questi eventi nel namespace globale di uno dei miei moduli (in modo che sappia che l'iscrizione all'evento avverrà prima che l'evento venga emesso). Mi registro come questo:

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

Nelle mie dichiarazioni di registro ottengo il seguente:

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] 

Quindi posso dire che io mando sia un evento app e un evento di dispositivo con il bla tag ed io mi sono registrato per ascoltare l'evento blah sia con DeviceEventEmitter che con NativeAppEventEmitters ma non ricevo il richiamo negli ascoltatori.

Cosa sto facendo male ?? Grazie per aver letto!

+0

A prima vista questo sembra OK. DeviceEventEmitter è esposto in react-native.js. Esaminando il modulo AppState ad esempio: https://github.com/facebook/react-native/blob/ad8a33586410c6f9048983f64f8f86e0715e73b8/Libraries/AppState/AppState.js Quello che potresti provare è trovare un modulo di terze parti che emette eventi e guarda il suo codice: https://js.coach/ –

+0

Grazie per la rapida risposta Martin. Ho cercato degli esempi che utilizzano NativeAppEventEmitter o DeviceEventEmitter e tutto ciò che fanno sembra lo stesso di quello che ho. L'unica cosa che posso pensare è che, poiché EventEmitter è una sua classe, sto eseguendo un alloc/init standard per ottenere un'istanza prima che possa accedere al metodo emitEvent. Il fatto che lo stia semplicemente assegnando alle mie condizioni avrà qualche effetto? –

+0

Stai creando nuove istanze EventEmitter da [EventEmitter alloc] init]? In tal caso, è possibile eseguire il debug del valore di _bridge nel metodo emitEvent? – halilb

risposta

2

Ho provato l'invio di eventi e sembra bridge non è inizializzata quando si crea nuovo EventEmitter casi manualmente utilizzando [EventEmitter alloc] init]

Si dovrebbe lasciare reagire nativo creare istanze. Ho controllato i componenti nativi e stanno utilizzando il metodo -(void)setBridge:(RCTBridge *)bridge per eseguire il lavoro di inizializzazione. Si prega di controllare RCTLinkingManager per vedere un esempio. Sta usando NSNotificationCenter per gestire gli eventi.

// 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

Questo mi ha indirizzato nella giusta direzione, grazie! –

3

È possibile utilizzare NativeEventEmitter

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

In ObjectiveC, è possibile creare

#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"]; 

ho scritto esempio di esempio per gestire l'evento da reagire nativo per ObjectiveC e contraria. https://github.com/lengocgiang/event-listener Spero che questo aiuto !!

+0

Ha importanza quale sia l'ordine di ciascun 'init'? La parte ReactNative della parte Obj-C? – Trip

1

Nel mio caso ho funzionato mantenendo un valore del bridge da RCTRootView e passandolo all'istanza Emitter.

@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]; 
} 

Nel mio Emitter Classe:

#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 * notifica = [RNNotification allocWithZone: nil]; [notifica sendNotificationToReactNative] Ho provato tutto sopra e non sono riuscito a farlo funzionare nella mia app.

Infine this ha funzionato per me.

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

e mentre initing la funzione

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