美文网首页
react-native 原生向JS端传递消息思考

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

作者: 一只小香猪_55c5 | 来源:发表于2020-09-20 13:04 被阅读0次

    原生往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类的那一套逻辑。

    参考

    参考文章

    相关文章

      网友评论

          本文标题:react-native 原生向JS端传递消息思考

          本文链接:https://www.haomeiwen.com/subject/egnuyktx.html