react-native 原生向JS端传递消息思考

2020-09-20  本文已影响0人  一只小香猪_55c5

原生往js层传递消息的方式

*iOS端是继承RCTEventEmitter,然后调用sendEventWithName方法


[self sendEventWithName:@"EventReminder" body:nil];

*Android端


getReactApplicationContext()   

         .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)

         .emit("EventReminder", null);

android

通过 RCTDeviceEventEmitter 模块进行原生与js的交互,所以在js层直接使用 RCTDeviceEventEmitter来注册监听
例如:

var emitter = require("RCTDeviceEventEmitter")

emitter.addListener("EventReminder",(e)=>{

  console.log("guangy get event in RCTDeviceEventEmitter")

})

或者


import {DeviceEventEmitter} from "react-native"

DeviceEventEmitter.addListener("EventReminder",(e)=>{



})

对应的调用方式


 import {DeviceEventEmitter} from "react-native"


import {DeviceEventEmitter} from "react-native"

DeviceEventEmitter.emit("EventReminder", params);

iOS

android 上两种注册方式都不会响应回调,iOS需要创建RCTEventEmitter的子类,在子类中处理js端的注册监听

针对sendEventWithName方法的实现,查看源码


- (void)sendEventWithName:(NSString *)eventName body:(id)body

{

...(省略部分代码)

`关键代码`

  if (_listenerCount > 0) {

    [_bridge enqueueJSCall:@"RCTDeviceEventEmitter"

                    method:@"emit"

                      args:body ? @[eventName, body] : @[eventName]

                completion:NULL];

  } 

...(省略部分代码)

}

其实RCTEventEmitter也是通过RCTDeviceEventEmitter进行注册通知的,但是它有一个控制值_listenerCount,而_listenerCount的数据类型为NSInteger所以默认初始值为0,其中_listenerCount代码的逻辑查看源码(主要):

// _listenerCount 增加


RCT_EXPORT_METHOD(addListener:(NSString *)eventName)

{

  if (RCT_DEBUG && ![[self supportedEvents] containsObject:eventName]) {

    RCTLogError(@"`%@` is not a supported event type for %@. Supported events are: `%@`",

                eventName, [self class], [[self supportedEvents] componentsJoinedByString:@"`, `"]);

  }

  _listenerCount++;

  if (_listenerCount == 1) {

    [self startObserving];

  }

}

// _listenerCount 减少


RCT_EXPORT_METHOD(removeListeners:(double)count)

{

  int currentCount = (int)count;

  if (RCT_DEBUG && currentCount > _listenerCount) {

    RCTLogError(@"Attempted to remove more %@ listeners than added", [self class]);

  }

  _listenerCount = MAX(_listenerCount - currentCount, 0);

  if (_listenerCount == 0) {

    [self stopObserving];

  }

}

所以js层必须通过如下方式进行addListener方法的调用:


const { RNCarrotEmitter, RNListenerManager } = NativeModules;

const listenerManager = new NativeEventEmitter(RNListenerManager);

// 调用 addListener 从而修改_listenerCount 属性

listenerManager.addListener(name, listenerResult);

查看NativeEventEmitter代码块中关于addListener方法调用:


addListener(

    eventType: string,

    listener: Function,

    context: ?Object,

  ): EmitterSubscription {

    if (this._nativeModule != null) {

      this._nativeModule.addListener(eventType);

    }

    return super.addListener(eventType, listener, context);

  }

这里调用了原生模块的addListener方法(即RCTEventEmitter中的addListener方法),使_listenerCount加1。所以在iOS端,因为原生代码中通过继承RCTEventEmitter类来发送消息,js层就必须使用NativeEventEmitter来注册监听,否则的话,原生层连消息都不会发出去。但是在Android端,因为底层实现就是直接给RCTDeviceEventEmitter发消息,不像iOS端有RCTEventEmitter类的那一套逻辑。

参考

参考文章

上一篇 下一篇

猜你喜欢

热点阅读