即使沒(méi)有被JavaScript調(diào)用,原生模塊也可以給JavaScript發(fā)送事件通知示启。最好的方法是繼承RCTEventEmitter兢哭,重寫(xiě)supportedEvents
方法并調(diào)用[self sendEventWithName:]
。
OC 實(shí)現(xiàn)如下
RNNotificationManager.h
#import <RCTViewManager.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface RNNotificationManager : RCTEventEmitter <RCTBridgeModule>
@end
RNNotificationManager.m
#import "RNNotificationManager.h"
NSString *const kEventEmitterManagerEvent = @"EventEmitterManagerEvent";
@implementation RNNotificationManager
RCT_EXPORT_MODULE()
// RN組件 發(fā)送事件通知
RCT_EXPORT_METHOD(postNotificationEvent:(NSString *)name)
{
RCTLogInfo(@"postNotificationEvent->:%@",name);
[self sendEventWithName:kEventEmitterManagerEvent body:name];
}
// 導(dǎo)出常量
- (NSDictionary<NSString *, NSString *> *)constantsToExport {
return @{ @"Myconstant": kEventEmitterManagerEvent,};
}
/**
* Override this method to return an array of supported event names.
* Attempting to observe or send an event that isn't included in this list will result in an error.
* 重寫(xiě)此方法,返回支持的事件名稱(chēng)的數(shù)組夫嗓。
*
* 試圖觀察或發(fā)送不包含在該列表中的事件,將導(dǎo)致錯(cuò)誤迟螺。
* RCTEventEmitter 會(huì)檢查 supportedEvents 并只發(fā)送支持的事件
*/
- (NSArray<NSString *> *)supportedEvents {
return @[kEventEmitterManagerEvent,];
}
@end
也有如下這種方式調(diào)用的,可能是沒(méi)有繼承RCTEventEmitter,沒(méi)有測(cè)試,可參考測(cè)試一下冲秽。
// 將消息轉(zhuǎn)發(fā)到JS中
[self.bridge.eventDispatcher sendAppEventWithName:@"testNotification" body:@{@"name": eventName}];
在JS中接收OC發(fā)送過(guò)來(lái)的通知
import { NativeEventEmitter, NativeModules } from 'react-native';
class RNTalk extends Component {
componentWillMount(){
// 拿到原生模塊
var EventEmitterManager = NativeModules.RNNotificationManager;
// 創(chuàng)建自定義事件接口
const eventEmitterManagerEmitter = new NativeEventEmitter(EventEmitterManager);
// 導(dǎo)出常量
const EventEmitterManagerEvent = EventEmitterManager.Myconstant;
// 監(jiān)聽(tīng)原生 接收原生發(fā)來(lái)的通知
/**
* addListener函數(shù)
* 第一個(gè)參數(shù)要和OC方法中的name參數(shù)相同,
* 第二個(gè)函數(shù)參數(shù)的參數(shù)為OC方法中的body。
* 所以O(shè)C需要傳遞給JS的數(shù)據(jù)通過(guò)body來(lái)傳輸锉桑。
*/
this.listener = eventEmitterManagerEmitter.addListener(
EventEmitterManagerEvent,
(data) => {console.log('通知來(lái)了-->'+data)}
);
}
// 別忘了取消訂閱民轴,通常在componentWillUnmount生命周期方法中實(shí)現(xiàn)后裸。
componentWillUnmount(){
this.listener.remove();
}
//發(fā)送通知
_postNotification(){
var EventEmitterManager = NativeModules.RNNotificationManager;
// 調(diào)用原生模塊 postNotificationEvent方法 發(fā)送通知消息
EventEmitterManager.postNotificationEvent('張楊事件傳遞');
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress= {()=>this._postNotification()}>
<Text>發(fā)送通知</Text>
</TouchableOpacity>
</View>
);
}
}
同OC中的通知一樣微驶,JS中的通知
使用完畢后也要進(jìn)行釋放因苹,同樣一般寫(xiě)在視圖被釋放的時(shí)候容燕。
componentWillUnmount(){
this.listener.remove();
}
優(yōu)化無(wú)監(jiān)聽(tīng)處理的事件
如果你發(fā)送了一個(gè)事件卻沒(méi)有任何監(jiān)聽(tīng)處理,則會(huì)因此收到一個(gè)資源警告。要優(yōu)化因此帶來(lái)的額外開(kāi)銷(xiāo)哮翘,你可以在你的RCTEventEmitter子類(lèi)中覆蓋startObserving和stopObserving方法阻课。
@implementation CalendarManager
{
bool hasListeners;
}
// 在添加第一個(gè)監(jiān)聽(tīng)函數(shù)時(shí)觸發(fā)
-(void)startObserving {
hasListeners = YES;
// Set up any upstream listeners or background tasks as necessary
}
// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
hasListeners = NO;
// Remove upstream listeners, stop unnecessary background tasks
}
- (void)calendarEventReminderReceived:(NSNotification *)notification
{
NSString *eventName = notification.userInfo[@"name"];
if (hasListeners) { // Only send events if anyone is listening
[self sendEventWithName:@"EventReminder" body:@{@"name": eventName}];
}
}