即使没有被JavaScript调用,原生模块也可以给JavaScript发送事件通知。最好的方法是继承RCTEventEmitter,重写supportedEvents
方法并调用[self sendEventWithName:]
。
OC 实现如下
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组件 发送事件通知
RCT_EXPORT_METHOD(postNotificationEvent:(NSString *)name)
{
RCTLogInfo(@"postNotificationEvent->:%@",name);
[self sendEventWithName:kEventEmitterManagerEvent body:name];
}
// 导出常量
- (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.
* 重写此方法,返回支持的事件名称的数组。
*
* 试图观察或发送不包含在该列表中的事件,将导致错误。
* RCTEventEmitter 会检查 supportedEvents 并只发送支持的事件
*/
- (NSArray<NSString *> *)supportedEvents {
return @[kEventEmitterManagerEvent,];
}
@end
也有如下这种方式调用的,可能是没有继承RCTEventEmitter,没有测试,可参考测试一下。
// 将消息转发到JS中
[self.bridge.eventDispatcher sendAppEventWithName:@"testNotification" body:@{@"name": eventName}];
在JS中接收OC发送过来的通知
import { NativeEventEmitter, NativeModules } from 'react-native';
class RNTalk extends Component {
componentWillMount(){
// 拿到原生模块
var EventEmitterManager = NativeModules.RNNotificationManager;
// 创建自定义事件接口
const eventEmitterManagerEmitter = new NativeEventEmitter(EventEmitterManager);
// 导出常量
const EventEmitterManagerEvent = EventEmitterManager.Myconstant;
// 监听原生 接收原生发来的通知
/**
* addListener函数
* 第一个参数要和OC方法中的name参数相同,
* 第二个函数参数的参数为OC方法中的body。
* 所以OC需要传递给JS的数据通过body来传输。
*/
this.listener = eventEmitterManagerEmitter.addListener(
EventEmitterManagerEvent,
(data) => {console.log('通知来了-->'+data)}
);
}
// 别忘了取消订阅,通常在componentWillUnmount生命周期方法中实现。
componentWillUnmount(){
this.listener.remove();
}
//发送通知
_postNotification(){
var EventEmitterManager = NativeModules.RNNotificationManager;
// 调用原生模块 postNotificationEvent方法 发送通知消息
EventEmitterManager.postNotificationEvent('张杨事件传递');
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress= {()=>this._postNotification()}>
<Text>发送通知</Text>
</TouchableOpacity>
</View>
);
}
}
同OC中的通知一样,JS中的通知
使用完毕后也要进行释放,同样一般写在视图被释放的时候。
componentWillUnmount(){
this.listener.remove();
}
优化无监听处理的事件
如果你发送了一个事件却没有任何监听处理,则会因此收到一个资源警告。要优化因此带来的额外开销,你可以在你的RCTEventEmitter子类中覆盖startObserving和stopObserving方法。
@implementation CalendarManager
{
bool hasListeners;
}
// 在添加第一个监听函数时触发
-(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}];
}
}