精华内容
下载资源
问答
  • 1ReactNative源码篇:源码初识2ReactNative源码篇:代码调用3ReactNative源码篇:启动流程4ReactNative源码篇:渲染原理5ReactNative源码篇:线程模型6ReactNative源码篇:通信机制 源码地址:ht

    本篇系列文章主要分析ReactNative源码,分析ReactNative的启动流程、渲染原理、通信机制与线程模型等方面内容。

    源码地址:https://github.com/facebook/react-native

    源码版本:Build Status Circle CI npm version

    本篇文章是《ReactNative源码篇》的第一篇文章,刚开始,我们先不对源码做深入的分析,我们先要对源码的结构和ReactNative的框架有个大致的印象, 
    由此便引出了本篇文章需要讨论的两个问题:

    1. ReactNative系统框架是怎样的?
    2. ReactNative系统框架的主线在哪里,有哪些支线,如何去分析这些线路?
    • 1
    • 2

    好,我们先来看第一个问题。

    ReactNative系统框架概述

    ReactNative源码结构图

    - jni:ReactNative的好多机制都是由CC++实现的,这部分便是用来载入SO库。
    - perftest:测试配置
    - proguard:混淆
    - quicklog:log输出
    - react:ReactNative源码的主要内容,也是我们分析的主要内容。
    - systrace:system trace
    - yoga:瑜伽?哈哈,并不是,是facebook开源的前端布局引擎
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    react依赖另外几个包,它们的调用关系如下图所示:

    ReactNative系统框架图如下所示:

    注:JSCore,即JavaScriptCore,JS解析的核心部分,IOS使用的是内置的JavaScriptCore,Androis上使用的是https://webkit.org/家的jsc.so。

    ReactNative系统框架主线与支线

    从上面对ReactNative系统框架的分析,我们很容易看出源码的主线就在于ReactNative的启动流程、UI的绘制与渲染以及双边通信(Java调用JS,JS调用Java)。

    源码主线:

    1 ReactNative应用启动流程
    2 ReactNative应用UI的绘制与渲染
    3 ReactNative应用通信机制
    3 ReactNative应用线程模型
    • 1
    • 2
    • 3
    • 4

    源码支线:

    1 ReactNative运行时的异常以及异常的捕获与处理。
    2 SOLoader加载动态链接库
    3 ReactNative触摸事件处理机制
    • 1
    • 2
    • 3

    在正式开始分析源码之前,我们先简单介绍一下各个类的作用,让大家先有个大概的印象,方便以后的讲解。

    ReactContext(Java层)

    继承于ContextWrapper,是RN应用的上下文,通过getContext()去获得,通过它可以访问RN核心类的实现。
    • 1

    ReactInstanceManagerImpl/ReactInstanceManagerImpl(Java层)

    RN应用总的管理类,创建ReactContext、CatalystInstance等类,解析ReactPackage生成映射表,并且配合ReactRootView管理View的创建与生命周期等功能。
    • 1

    CatalystInstance/CatalystInstanceImpl(Java层/C++层)

    RN应用Java层、C++层、JS层通信总管理类,总管Java层、JS层核心Module映射表与回调,三端通信的入口与桥梁。
    • 1

    NativeToJsBridge(C++层)

    Java调用JS的桥梁,用来调用JS Module,回调Java。
    • 1

    JsToNativeBridge(C++层)

    JS调用Java的桥梁,用来调用Java Module
    • 1

    JSCExecutor(C++层)

    管理WebKit的JavaScriptCore,JS与C++的转换桥接都在这里进行中转处理。
    • 1

    MessageQueue(JS层)

    JS调用队列,调用Java Module或者JS Module的方法,处理回调。
    • 1

    JavaScriptModule(Java层)

    JS Module,负责JS到Java的映射调用格式声明,由CatalystInstance统一管理。
    • 1

    ReactContextBaseJavaModule/BaseJavaModule/NativeModule(Java层)

    Java Module,负责Java到Js的映射调用格式声明,由CatalystInstance统一管理。
    • 1

    JavascriptModuleRegistry(Java层)

    JS Module映射表
    • 1

    NativeModuleRegistry(Java层)

    Java Module映射表
    • 1

    附录

    为了方便大家理解,准备了导读PPT。

     
     
     
     
     
     
     
     
     
     
     
     

    展开全文
  • ReactNative源码

    千次阅读 2017-09-28 14:25:35
    本篇系列文章主要分析ReactNative源码,分析ReactNative的启动流程、渲染原理、通信机制与...1ReactNative源码篇:源码初识2ReactNative源码篇:代码调用3ReactNative源码篇:启动流程4ReactNative源码篇:渲染

    https://juejin.im/post/59cc51625188257a134ab5df

    本篇系列文章主要分析ReactNative源码,分析ReactNative的启动流程、渲染原理、通信机制与线程模型等方面内容。

    通信,指的是RN中Java与JS的通信,即JS中的JSX代码如何转化成Java层真实的View与事件的,以及JavaFile层又是如何调用JS来找出它需要的View与
    事件的。

    在上一篇文章ReactNative源码篇:启动流程中,我们知道RN应用在启动的时候会创建JavaScriptModule注册表(JavaScriptModuleRegistry)与NativeModule注册表(NativeModuleRegistry),RN中Java层
    与JS层的通信就是通过这两张表来完成的,我们来详细看一看。

    在正式开始分析通信机制之前,我们先了解和本篇文章相关的一些重要概念。

    在正式介绍通信机制之前,我们先来了解一些核心的概念。

    JavaScript Module注册表

    说起JavaScript Module注册表,我们需要先理解3个类/接口:JavaScriptModule、JavaScriptModuleRegistration、JavaScriptModuleRegistry。

    JavaScriptModule

    JavaScriptModule:这是一个接口,JS Module都会继承此接口,它表示在JS层会有一个相同名字的js文件,该js文件实现了该接口定义的方法,JavaScriptModuleRegistry会利用
    动态代理将这个接口生成代理类,并通过C++传递给JS层,进而调用JS层的方法。

    JavaScriptModuleRegistration

    JavaScriptModuleRegistration用来描述JavaScriptModule的相关信息,它利用反射获取接口里定义的Method。

    JavaScriptModuleRegistry

    JavaScriptModuleRegistry:JS Module注册表,内部维护了一个HashMap:HashMap<Class<? extends JavaScriptModule>, JavaScriptModuleRegistration> mModuleRegistrations,
    JavaScriptModuleRegistry利用动态代理生成接口JavaScriptModule对应的代理类,再通过C++传递到JS层,从而调用JS层的方法。

    Java Module注册表

    要理解Java Module注册表,我们同样也需要理解3个类/接口:NativeModule、ModuleHolder、NativeModuleRegistry。

    NativeModule

    NativeModule:是一个接口,实现了该接口则可以被JS层调用,我们在为JS层提供Java API时通常会继承BaseJavaModule/ReactContextBaseJavaModule,这两个类就
    实现了NativeModule接口。

    ModuleHolder

    ModuleHolder:NativeModule的一个Holder类,可以实现NativeModule的懒加载。

    NativeModuleRegistry

    NativeModuleRegistry:Java Module注册表,内部持有Map:Map<Class<? extends NativeModule>, ModuleHolder> mModules,NativeModuleRegistry可以遍历
    并返回Java Module供调用者使用。

    好,了解了这些重要概念,我们开始分析整个RN的通信机制。

    一 配置表的实现

    1.1 配置表的定义

    函数配置表定义在NativeModule.h中。

    struct MethodDescriptor {
      std::string name;
      // type is one of js MessageQueue.MethodTypes
      std::string type;
    
      MethodDescriptor(std::string n, std::string t)
          : name(std::move(n))
          , type(std::move(t)) {}
    };

    method的定义

    public class JavaModuleWrapper {
      public class MethodDescriptor {
        @DoNotStrip
        Method method;
        @DoNotStrip
        String signature;
        @DoNotStrip
        String name;
        @DoNotStrip
        String type;
      }
    }

    1.2 配置表的创建

    在文章ReactNative源码篇:启动流程中,我们可以知道在ReactInstanceManager执行createReactContext()时
    创建了JavaScriptModuleRegistry与NativeModuleRegistry这两张表,我们跟踪一下它们俩的创建流程,以及创建完成后各自的去向。

    通过上面分析我们可知JavaScriptModuleRegistry创建完成后由CatalystInstanceImpl实例所持有,供后续Java调用JS时使用。相当于Java层此时持有了一张JS模块表,它以后可以通过这个表去调用JS。
    而NativeModuleRegistry在CatalystInstanceImpl.initializeBridge()方法中被传入C++层,最终可以被JS层所拿到。

    public class CatalystInstanceImpl(
      private CatalystInstanceImpl(
          final ReactQueueConfigurationSpec ReactQueueConfigurationSpec,
          final JavaScriptExecutor jsExecutor,
          final NativeModuleRegistry registry,
          final JavaScriptModuleRegistry jsModuleRegistry,
          final JSBundleLoader jsBundleLoader,
          NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
    
        ...
    
        initializeBridge(
          new BridgeCallback(this),
          jsExecutor,
          mReactQueueConfiguration.getJSQueueThread(),
          mReactQueueConfiguration.getNativeModulesQueueThread(),
          mJavaRegistry.getJavaModules(this),//传入的是Collection<JavaModuleWrapper> ,JavaModuleWrapper是NativeHolder的一个Wrapper类,它对应了C++层JavaModuleWrapper.cpp.
          mJavaRegistry.getCxxModules());//传入的是Collection<ModuleHolder> ,ModuleHolder是NativeModule的一个Holder类,可以实现NativeModule的懒加载。
        FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
        mMainExecutorToken = getMainExecutorToken();
      }
    )

    这里我们注意一下传入C++的两个集合

    mJavaRegistry.getJavaModules(this):传入的是Collection<JavaModuleWrapper> ,JavaModuleWrapper是NativeHolder的一个Wrapper类,它对应了C++层JavaModuleWrapper.cpp,
    JS在Java的时候最终会调用到这个类的inovke()方法上。
    
    mJavaRegistry.getCxxModules()):传入的是Collection<ModuleHolder> ,ModuleHolder是NativeModule的一个Holder类,可以实现NativeModule的懒加载。

    我们继续跟踪这两个集合到了C++层之后的去向。

    CatalystInstanceImpl.cpp

    void CatalystInstanceImpl::initializeBridge(
        jni::alias_ref<ReactCallback::javaobject> callback,
        // This executor is actually a factory holder.
        JavaScriptExecutorHolder* jseh,
        jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
        jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
        jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
        jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
    
    
      instance_->initializeBridge(folly::make_unique<JInstanceCallback>(callback),
                                  jseh->getExecutorFactory(),
                                  folly::make_unique<JMessageQueueThread>(jsQueue),
                                  folly::make_unique<JMessageQueueThread>(moduleQueue),
                                  buildModuleRegistry(std::weak_ptr<Instance>(instance_),
                                                      javaModules, cxxModules));
    }

    这两个集合在CatalystInstanceImpl::initializeBridge()被打包成ModuleRegistry传入Instance.cpp.、,如下所示:

    ModuleRegistryBuilder.cpp

    std::unique_ptr<ModuleRegistry> buildModuleRegistry(
        std::weak_ptr<Instance> winstance,
        jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
        jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
    
      std::vector<std::unique_ptr<NativeModule>> modules;
      for (const auto& jm : *javaModules) {
        modules.emplace_back(folly::make_unique<JavaNativeModule>(winstance, jm));
      }
      for (const auto& cm : *cxxModules) {
        modules.emplace_back(
          folly::make_unique<CxxNativeModule>(winstance, cm->getName(), cm->getProvider()));
      }
      if (modules.empty()) {
        return nullptr;
      } else {
        return folly::make_unique<ModuleRegistry>(std::move(modules));
      }
    }

    打包好的ModuleRegistry通过Instance::initializeBridge()传入到NativeToJsBridge.cpp中,并在NativeToJsBridge的构造方法中传给JsToNativeBridge,以后JS如果调用Java就可以通过
    ModuleRegistry来进行调用。

    二 通信桥的实现

    关于整个RN的通信机制,可以用一句话来概括:

    JNI作为C++与Java的桥梁,JSC作为C++与JavaScript的桥梁,而C++最终连接了Java与JavaScript。

    RN应用通信桥结构图如下所示:

    2.1 关于通信桥在Java层中的实现

    从文章ReactNative源码篇:启动流程我们得知在

    在CatalystInstanceImpl构造方法中做了初始化通信桥的操作:

    public class CatalystInstanceImpl implements CatalystInstance {
    
    private CatalystInstanceImpl(
          final ReactQueueConfigurationSpec ReactQueueConfigurationSpec,
          final JavaScriptExecutor jsExecutor,
          final NativeModuleRegistry registry,
          final JavaScriptModuleRegistry jsModuleRegistry,
          final JSBundleLoader jsBundleLoader,
          NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
    
        ...
    
        //Native方法,调用initializeBridge()方法,并创建BridgeCallback实例,初始化Bridge。
        initializeBridge(
          new BridgeCallback(this),
          jsExecutor,
          mReactQueueConfiguration.getJSQueueThread(),
          mReactQueueConfiguration.getNativeModulesQueueThread(),
          mJavaRegistry.getJavaModules(this),
          mJavaRegistry.getCxxModules());
        FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
        mMainExecutorToken = getMainExecutorToken();
      }
    
      //在C++层初始化通信桥ReactBridge
      private native void initializeBridge(
          ReactCallback callback,
          JavaScriptExecutor jsExecutor,
          MessageQueueThread jsQueue,
          MessageQueueThread moduleQueue,
          Collection<JavaModuleWrapper> javaModules,
          Collection<ModuleHolder> cxxModules);
    }

    传入的几个参数:

    ReactCallback callback:CatalystInstanceImpl的静态内部类ReactCallback,负责接口回调。
    JavaScriptExecutor jsExecutor:JS执行器,将JS的调用传递给C++层。
    MessageQueueThread jsQueue.getJSQueueThread():JS线程,通过mReactQueueConfiguration.getJSQueueThread()获得,mReactQueueConfiguration通过ReactQueueConfigurationSpec.createDefault()创建。
    MessageQueueThread moduleQueue:Native线程,通过mReactQueueConfiguration.getNativeModulesQueueThread()获得,mReactQueueConfiguration通过ReactQueueConfigurationSpec.createDefault()创建。
    Collection<JavaModuleWrapper> javaModules:java modules,来源于mJavaRegistry.getJavaModules(this)。
    Collection<ModuleHolder> cxxModules):c++ modules,来源于mJavaRegistry.getCxxModules()。

    我们去跟踪它的函数调用链:

    CatalystInstanceImpl.initializeBridge() -> CatalystInstanceImpl::initializeBridge() -> Instance::initializeBridge()

    最终可以发现,Instance::initializeBridge()实现了ReactBridge(C++层对应JsToNativeBridge与NativeToJsBridge)的初始化。

    Instance.cpp

    void Instance::initializeBridge(
        std::unique_ptr<InstanceCallback> callback,
        std::shared_ptr<JSExecutorFactory> jsef,
        std::shared_ptr<MessageQueueThread> jsQueue,
        std::unique_ptr<MessageQueueThread> nativeQueue,
        std::shared_ptr<ModuleRegistry> moduleRegistry) {
      callback_ = std::move(callback);
    
      if (!nativeQueue) {
        // TODO pass down a thread/queue from java, instead of creating our own.
    
        auto queue = folly::make_unique<CxxMessageQueue>();
        std::thread t(queue->getUnregisteredRunLoop());
        t.detach();
        nativeQueue = std::move(queue);
      }
    
      jsQueue->runOnQueueSync(
        [this, &jsef, moduleRegistry, jsQueue,
         nativeQueue=folly::makeMoveWrapper(std::move(nativeQueue))] () mutable {
          //初始化NativeToJsBridge对象
          nativeToJsBridge_ = folly::make_unique<NativeToJsBridge>(
              jsef.get(), moduleRegistry, jsQueue, nativeQueue.move(), callback_);
    
          std::lock_guard<std::mutex> lock(m_syncMutex);
          m_syncReady = true;
          m_syncCV.notify_all();
        });
    
      CHECK(nativeToJsBridge_);
    }

    我们接着去C++层看看JsToNativeBridge与NativeToJsBridge的实现。

    2.2 关于通信桥在C++层的实现

    在C++层的Executor.h文件中定义了整个Java调用JS,JS调用Java的逻辑。

    Executor.h文件中定义了抽象类ExecutorDelegate,定义了执行Native Module的方法,它是JS调用Java的桥梁,JsToNativeBridge实现了该类的纯虚函数(抽象方法),该抽象
    类还持有JSExecutor(用来执行JS)的引用。

    class ExecutorDelegate {
     public:
      virtual ~ExecutorDelegate() {}
    
      virtual void registerExecutor(std::unique_ptr<JSExecutor> executor,
                                    std::shared_ptr<MessageQueueThread> queue) = 0;
      virtual std::unique_ptr<JSExecutor> unregisterExecutor(JSExecutor& executor) = 0;
    
      virtual std::shared_ptr<ModuleRegistry> getModuleRegistry() = 0;
    
      virtual void callNativeModules(
        JSExecutor& executor, folly::dynamic&& calls, bool isEndOfBatch) = 0;
      virtual MethodCallResult callSerializableNativeHook(
        JSExecutor& executor, unsigned int moduleId, unsigned int methodId, folly::dynamic&& args) = 0;
    };

    Executor.h文件中定义了抽象类JSExecutor,它定义了执行JS Module的方法,用来解释执行JS,JSCExecutor实现了该类中的纯虚函数(抽象方法),另一个类
    NativeToBridge与JsToNativeBridge相对应,它是Java调用JS的桥梁,NativeToBridge持有JSCExecutor的引用,如果NativeToBridge需要执行JS时就会
    去调用JSCExecutor。

    
    class JSExecutor {
    public:
      /**
       * Execute an application script bundle in the JS context.
       */
      virtual void loadApplicationScript(std::unique_ptr<const JSBigString> script,
                                         std::string sourceURL) = 0;
    
      /**
       * Add an application "unbundle" file
       */
      virtual void setJSModulesUnbundle(std::unique_ptr<JSModulesUnbundle> bundle) = 0;
    
      /**
       * Executes BatchedBridge.callFunctionReturnFlushedQueue with the module ID,
       * method ID and optional additional arguments in JS. The executor is responsible
       * for using Bridge->callNativeModules to invoke any necessary native modules methods.
       */
      virtual void callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) = 0;
    
      /**
       * Executes BatchedBridge.invokeCallbackAndReturnFlushedQueue with the cbID,
       * and optional additional arguments in JS and returns the next queue. The executor
       * is responsible for using Bridge->callNativeModules to invoke any necessary
       * native modules methods.
       */
      virtual void invokeCallback(const double callbackId, const folly::dynamic& arguments) = 0;
    
      virtual void setGlobalVariable(std::string propName,
                                     std::unique_ptr<const JSBigString> jsonValue) = 0;
      virtual void* getJavaScriptContext() {
        return nullptr;
      }
      virtual bool supportsProfiling() {
        return false;
      }
      virtual void startProfiler(const std::string &titleString) {}
      virtual void stopProfiler(const std::string &titleString, const std::string &filename) {}
      virtual void handleMemoryPressureUiHidden() {}
      virtual void handleMemoryPressureModerate() {}
      virtual void handleMemoryPressureCritical() {
        handleMemoryPressureModerate();
      }
      virtual void destroy() {}
      virtual ~JSExecutor() {}
    };

    2.3 关于通信桥在JS层的实现

    JS层Libraries/BatchedBridge包下面有3个JS文件:BatchedBridge.js、MessageQueue.js、NativeModules.js,它们封装了通信桥在JS层的实现。

    BatchedBridge.js

    'use strict';
    
    const MessageQueue = require('MessageQueue');
    const BatchedBridge = new MessageQueue();
    
    // Wire up the batched bridge on the global object so that we can call into it.
    // Ideally, this would be the inverse relationship. I.e. the native environment
    // provides this global directly with its script embedded. Then this module
    // would export it. A possible fix would be to trim the dependencies in
    // MessageQueue to its minimal features and embed that in the native runtime.
    
    Object.defineProperty(global, '__fbBatchedBridge', {
      configurable: true,
      value: BatchedBridge,
    });
    
    module.exports = BatchedBridge;

    可以看到在BatchedBridge中创建了MessageQueue对象。

    MessageQueue.js

    MessageQueue的实现有点长,我们来一步步看它的实现。先看MessageQueue的构造方法。

    class MessageQueue {
    
      //
      _callableModules: {[key: string]: Object};
      //队列,分别存放要调用的模块数组、方法数组、参数数组与数组大小
      _queue: [Array<number>, Array<number>, Array<any>, number];
      //回调函数数组,与_quueue一一对应,每个_queue中调用的方法,如果有回调方法,那么就在这个数组对应的下标上。
      _callbacks: [];
      //回调ID,自动增加。
      _callbackID: number;
      //调用函数ID,自动增加。
      _callID: number;
      _lastFlush: number;
      //消息队列事件循环开始时间
      _eventLoopStartTime: number;
    
      _debugInfo: Object;
      //Module Table,用于Native Module
      _remoteModuleTable: Object;
      //Method Table,用于Native Module
      _remoteMethodTable: Object;
    
      __spy: ?(data: SpyData) => void;
    
      constructor() {
        this._callableModules = {};
        this._queue = [[], [], [], 0];
        this._callbacks = [];
        this._callbackID = 0;
        this._callID = 0;
        this._lastFlush = 0;
        this._eventLoopStartTime = new Date().getTime();
    
        if (__DEV__) {
          this._debugInfo = {};
          this._remoteModuleTable = {};
          this._remoteMethodTable = {};
        }
    
        //绑定函数,也就是创建一个函数,使这个函数不论怎么调用都有同样的this值。
        (this:any).callFunctionReturnFlushedQueue = this.callFunctionReturnFlushedQueue.bind(this);
        (this:any).callFunctionReturnResultAndFlushedQueue = this.callFunctionReturnResultAndFlushedQueue.bind(this);
        (this:any).flushedQueue = this.flushedQueue.bind(this);
        (this:any).invokeCallbackAndReturnFlushedQueue = this.invokeCallbackAndReturnFlushedQueue.bind(this);
      }
    }

    NativeModules.jS

    NativeModules描述了Module的结构,用于解析并生成Module。

    Module的结构定义如下所示:

    type ModuleConfig = [
      string, /* name */
      ?Object, /* constants */
      Array<string>, /* functions */
      Array<number>, /* promise method IDs */
      Array<number>, /* sync method IDs */
    ];

    举例

    {
      "remoteModuleConfig": {
        "Logger": {
          "constants": { /* If we had exported constants... */ },
          "moduleID": 1,
          "methods": {
            "requestPermissions": {
              "type": "remote",
              "methodID": 1
            }
          }
        }
      }
    }
    {
      'ToastAndroid': {
        moduleId: 0,
        methods: {
          'show': {
            methodID: 0
          }
        },
        constants: {
          'SHORT': '0',
          'LONG': '1'
        }
      },
      'moduleB': {
        moduleId: 0,
        methods: {
          'method1': {
            methodID: 0
          }
        },
        'key1': 'value1',
        'key2': 'value2'
      }
    }

    接下来,我们分析一下JS代码调用Java代码的流程。

    三 JS层调用Java层

    RN应用通信机制流程图(JS->Java)如下所示:

    举例

    同样的,我们先来看一个JS代码调用Java代码的例子,我们写一个ToastModule供JS代码调用。

    1 编写ToastModule继承于ReactContextBaseJavaModule,该ToastModule实现具体的功能供JS代码调用。

    public class ToastModule extends ReactContextBaseJavaModule {
    
      private static final String DURATION_SHORT_KEY = "SHORT";
      private static final String DURATION_LONG_KEY = "LONG";
    
      public ToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
      }
    
      //返回模块名字供JS代码调用
      @Override
      public String getName() {
        return "ToastAndroid";
      }
    
      //返回常量供JS代码调用
      @Override
      public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
        constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
        return constants;
      }
    
      //暴露给JS代码的方法,加@ReactMethod注解,且该方法总是void。
      @ReactMethod
      public void show(String message, int duration) {
        Toast.makeText(getReactApplicationContext(), message, duration).show();
      }
    }

    2 编写类继承ReactPackage,注册ToastModule。

    public class AnExampleReactPackage implements ReactPackage {
    
      @Override
      public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
      }
    
      @Override
      public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
      }
    
      @Override
      public List<NativeModule> createNativeModules(
                                  ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
    
        modules.add(new ToastModule(reactContext));
    
        return modules;
      }
    
    }
    protected List<ReactPackage> getPackages() {
        return Arrays.<ReactPackage>asList(
                new MainReactPackage(),
                new AnExampleReactPackage()); // <-- Add this line with your package name.
    }

    3 为了方便JS代码调用,编写一个JS Module来包装Native Module的功能。

    
    'use strict';
    /**
     * This exposes the native ToastAndroid module as a JS module. This has a
     * function 'show' which takes the following parameters:
     *
     * 1. String message: A string with the text to toast
     * 2. int duration: The duration of the toast. May be ToastAndroid.SHORT or
     *    ToastAndroid.LONG
     */
    import { NativeModules } from 'react-native';
    module.exports = NativeModules.ToastAndroid;

    4 最后我们就可以直接在JS代码中进行调用。

    
    import ToastAndroid from './ToastAndroid';
    
    ToastAndroid.show('Awesome', ToastAndroid.SHORT);

    以上便是JS代码调用Java代码的全部流程,我们来具体分析它的实现细节。

    从上面例子中,我们可以看出,调用的第一步就是从JS层的NativeModule注册表中拿到对应Java层的Java Module。但是JS在调用Java并不是通过接口来进行的,而是对应的
    参数moduleID、methodID都push到一个messageQueue中,等待Java层的事件来驱动它,当Java层的事件传递过来以后,JS层把messageQUeue中的所有数据返回到Java层,
    再通过注册表JavaRegistry去调用方法。

    JS层调用Java层实现流程:

    1 JS将需要调用的方法的moduleID、methodID与arguments一块push到MessageQueue中,等待Java层的事件驱动。
    2

    我们们再调用Java代码时都通过NativeModules.xxxModule.xxxMethod()的方式来调用,我们先来看看NativeModules.js的实现。

    3.1 NativeModules.xxxModule.xxxMethod()

    当我们用NativeModules.xxxModule.xxxMethod()这种方式去调用时,JS就会通过JS层的NativeModules去查找相对应的Java Module。

    NativeModules.js

    
    let NativeModules : {[moduleName: string]: Object} = {};
    
      //可以看到Native被赋值为global.nativeModuleProxy,nativeModuleProxy是一个全局变量,顾名思义,它是NativeModules.js在C++层的代理。
      NativeModules = global.nativeModuleProxy;
    } else {
      const bridgeConfig = global.__fbBatchedBridgeConfig;
      invariant(bridgeConfig, '__fbBatchedBridgeConfig is not set, cannot invoke native modules');
    
      (bridgeConfig.remoteModuleConfig || []).forEach((config: ModuleConfig, moduleID: number) => {
        // Initially this config will only contain the module name when running in JSC. The actual
        // configuration of the module will be lazily loaded.
        const info = genModule(config, moduleID);
        if (!info) {
          return;
        }
    
        if (info.module) {
          NativeModules[info.name] = info.module;
        }
        // If there's no module config, define a lazy getter
        else {
          defineLazyObjectProperty(NativeModules, info.name, {
            get: () => loadModule(info.name, moduleID)
          });
        }
      });
    }
    
    module.exports = NativeModules;

    nativeModuleProxy实质上是在启动流程中,JSCExecutor::JSCExecutor()在创建时通过installGlobalProxy(m_context, "nativeModuleProxy", exceptionWrapMethod<&JSCExecutor::getNativeModule>())
    创建的,所以当JS调用NativeModules时,实际上在调用JSCExecutor::getNativeModule()方法,我们来看一看该方法的实现。

    3.2 JSCExecutor::getNativeModule(JSObjectRef object, JSStringRef propertyName)

    
    JSValueRef JSCExecutor::getNativeModule(JSObjectRef object, JSStringRef propertyName) {
      if (JSC_JSStringIsEqualToUTF8CString(m_context, propertyName, "name")) {
        return Value(m_context, String(m_context, "NativeModules"));
      }
      //m_nativeModules的类型是JSCNativeModules
      return m_nativeModules.getModule(m_context, propertyName);
    }

    该方法进一步调用JSCNativeModules.cpp的getModule()方法,我们来看看它的实现。

    3.3 JSCNativeModules::getModule(JSContextRef context, JSStringRef jsName)

    JSCNativeModules.cpp

    JSValueRef JSCNativeModules::getModule(JSContextRef context, JSStringRef jsName) {
      if (!m_moduleRegistry) {
        return Value::makeUndefined(context);
      }
    
      std::string moduleName = String::ref(context, jsName).str();
    
      const auto it = m_objects.find(moduleName);
      if (it != m_objects.end()) {
        return static_cast<JSObjectRef>(it->second);
      }
    
      //调用该方法,通过JSC获取全局设置的JS属性,然后通过JNI查找Java层注册表,再触发JS层方法。
      auto module = createModule(moduleName, context);
      if (!module.hasValue()) {
        return Value::makeUndefined(context);
      }
    
      // Protect since we'll be holding on to this value, even though JS may not
      module->makeProtected();
    
      auto result = m_objects.emplace(std::move(moduleName), std::move(*module)).first;
      return static_cast<JSObjectRef>(result->second);
    }
    
    folly::Optional<Object> JSCNativeModules::createModule(const std::string& name, JSContextRef context) {
      if (!m_genNativeModuleJS) {
    
        auto global = Object::getGlobalObject(context);
        //NativeModules.js中将全局变量__fbGenNativeModule指向了函数NativeModules::gen()方法,此处
        //便是去获取JSC去调用这个方法
        m_genNativeModuleJS = global.getProperty("__fbGenNativeModule").asObject();
        m_genNativeModuleJS->makeProtected();
    
        // Initialize the module name list, otherwise getModuleConfig won't work
        // TODO (pieterdb): fix this in ModuleRegistry
        m_moduleRegistry->moduleNames();
      }
      //获取Native配置表
      auto result = m_moduleRegistry->getConfig(name);
      if (!result.hasValue()) {
        return nullptr;
      }
    
      //调用NativeModules::gen()方法
      Value moduleInfo = m_genNativeModuleJS->callAsFunction({
        Value::fromDynamic(context, result->config),
        Value::makeNumber(context, result->index)
      });
      CHECK(!moduleInfo.isNull()) << "Module returned from genNativeModule is null";
    
      return moduleInfo.asObject().getProperty("module").asObject();
    }

    上面的方法实现的功能分为2步:

    1 调用ModuleRegistry::getConfig()获取ModuleConfig。
    2 通过JSC调用NativeModules.js的genModule()方法

    ModuleRegistry是从Java层传递过来额JavaModuleRegistry,ModuleRegistry::getConfig()查询Java Module的配置表,然后发送给NativeModule.js生成对应的JS Module。

    ModuleRegistry.cpp

    
    folly::Optional<ModuleConfig> ModuleRegistry::getConfig(const std::string& name) {
      SystraceSection s("getConfig", "module", name);
      auto it = modulesByName_.find(name);
      if (it == modulesByName_.end()) {
        return nullptr;
      }
    
      CHECK(it->second < modules_.size());
      //modules_列表来源于CatalystInstanceImpl::initializeBridge()
      //module实质上是ModuleRegistryHolder.cpp的构造函数汇总将Java层传递过来的Module包装成CxxNativeModule与JavaModule,这两个都是NativeModule的子类。
      NativeModule* module = modules_[it->second].get();
    
      //string name, object constants, array methodNames准备创建一个动态对象。
      // string name, object constants, array methodNames (methodId is index), [array promiseMethodIds], [array syncMethodIds]
      folly::dynamic config = folly::dynamic::array(name);
    
      {
        SystraceSection s("getConstants");
        //通过反射调用Java层的JavaModuleWrapper.getContants()shi方法。
        config.push_back(module->getConstants());
      }
    
      {
        SystraceSection s("getMethods");
        //通过反射调用Java层的JavaModuleWrapper.getMethods()方法,也就是BaseJavaModule.getMethods(),该方法内部会调用
        //findMethos()方法查询带有ReactMoethod注解的方法。
        std::vector<MethodDescriptor> methods = module->getMethods();
    
        folly::dynamic methodNames = folly::dynamic::array;
        folly::dynamic promiseMethodIds = folly::dynamic::array;
        folly::dynamic syncMethodIds = folly::dynamic::array;
    
        for (auto& descriptor : methods) {
          // TODO: #10487027 compare tags instead of doing string comparison?
          methodNames.push_back(std::move(descriptor.name));
          if (descriptor.type == "promise") {
            promiseMethodIds.push_back(methodNames.size() - 1);
          } else if (descriptor.type == "sync") {
            syncMethodIds.push_back(methodNames.size() - 1);
          }
        }
    
        if (!methodNames.empty()) {
          config.push_back(std::move(methodNames));
          if (!promiseMethodIds.empty() || !syncMethodIds.empty()) {
            config.push_back(std::move(promiseMethodIds));
            if (!syncMethodIds.empty()) {
              config.push_back(std::move(syncMethodIds));
            }
          }
        }
      }
    
      if (config.size() == 1) {
        // no constants or methods
        return nullptr;
      } else {
        return ModuleConfig({it->second, config});
      }
    }

    获取到相应ModuleConfig就会去调用NativeModules.js的genModule()生成JS将要调用对应的JS Module。

    3.4 NativeModules.genModule(config: ?ModuleConfig, moduleID: number): ?{name: string, module?: Object}

    NativeModules.js

    
    // export this method as a global so we can call it from native
    global.__fbGenNativeModule = genModule;
    
    function genModule(config: ?ModuleConfig, moduleID: number): ?{name: string, module?: Object} {
      if (!config) {
        return null;
      }
    
      //通过JSC拿到C++中从Java层获取的Java Module的注册表
      const [moduleName, constants, methods, promiseMethods, syncMethods] = config;
      invariant(!moduleName.startsWith('RCT') && !moduleName.startsWith('RK'),
        'Module name prefixes should\'ve been stripped by the native side ' +
        'but wasn\'t for ' + moduleName);
    
      if (!constants && !methods) {
        // Module contents will be filled in lazily later
        return { name: moduleName };
      }
    
      const module = {};
      //遍历构建Module的属性与方法
      methods && methods.forEach((methodName, methodID) => {
        const isPromise = promiseMethods && arrayContains(promiseMethods, methodID);
        const isSync = syncMethods && arrayContains(syncMethods, methodID);
        invariant(!isPromise || !isSync, 'Cannot have a method that is both async and a sync hook');
        const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async';
        //生成Module的函数方法
        module[methodName] = genMethod(moduleID, methodID, methodType);
      });
      Object.assign(module, constants);
    
      if (__DEV__) {
        BatchedBridge.createDebugLookup(moduleID, moduleName, methods);
      }
    
      return { name: moduleName, module };
    }

    该方法通过JSC拿到C++中从Java层获取的Java Module的注册表,遍历构建Module的属性与方法,并调用genMethod()生成Module的函数方法,我们调用ToastAndroid.show(‘Awesome’, ToastAndroid.SHORT)时
    实际上就是在调用genMethod()生成的方法,我们来看一看它的实现。

    NativeModules.js

    //该函数会根据函数类型的不同做不同的处理,但最终都会调用BatchedBridge.enqueueNativeCall()方法。
    function genMethod(moduleID: number, methodID: number, type: MethodType) {
      let fn = null;
      if (type === 'promise') {
        fn = function(...args: Array<any>) {
          return new Promise((resolve, reject) => {
            BatchedBridge.enqueueNativeCall(moduleID, methodID, args,
              (data) => resolve(data),
              (errorData) => reject(createErrorFromErrorData(errorData)));
          });
        };
      } else if (type === 'sync') {
        fn = function(...args: Array<any>) {
          return global.nativeCallSyncHook(moduleID, methodID, args);
        };
      } else {
        fn = function(...args: Array<any>) {
          const lastArg = args.length > 0 ? args[args.length - 1] : null;
          const secondLastArg = args.length > 1 ? args[args.length - 2] : null;
          const hasSuccessCallback = typeof lastArg === 'function';
          const hasErrorCallback = typeof secondLastArg === 'function';
          hasErrorCallback && invariant(
            hasSuccessCallback,
            'Cannot have a non-function arg after a function arg.'
          );
          const onSuccess = hasSuccessCallback ? lastArg : null;
          const onFail = hasErrorCallback ? secondLastArg : null;
          const callbackCount = hasSuccessCallback + hasErrorCallback;
          args = args.slice(0, args.length - callbackCount);
          BatchedBridge.enqueueNativeCall(moduleID, methodID, args, onFail, onSuccess);
        };
      }
      fn.type = type;
      return fn;
    }

    该函数会根据函数类型的不同做不同的处理,但最终都会调用BatchedBridge.enqueueNativeCall()方法,我们来看看它的实现。

    3.5 MessageQueue.enqueueNativeCall(moduleID: number, methodID: number, params: Array, onFail: ?Function, onSucc: ?Function)

    MessageQueue.js

    
      enqueueNativeCall(moduleID: number, methodID: number, params: Array<any>, onFail: ?Function, onSucc: ?Function) {
        if (onFail || onSucc) {
          if (__DEV__) {
            const callId = this._callbackID >> 1;
            this._debugInfo[callId] = [moduleID, methodID];
            if (callId > DEBUG_INFO_LIMIT) {
              delete this._debugInfo[callId - DEBUG_INFO_LIMIT];
            }
          }
          onFail && params.push(this._callbackID);
          /* $FlowFixMe(>=0.38.0 site=react_native_fb,react_native_oss) - Flow error
           * detected during the deployment of v0.38.0. To see the error, remove
           * this comment and run flow */
          this._callbacks[this._callbackID++] = onFail;
          onSucc && params.push(this._callbackID);
          /* $FlowFixMe(>=0.38.0 site=react_native_fb,react_native_oss) - Flow error
           * detected during the deployment of v0.38.0. To see the error, remove
           * this comment and run flow */
          this._callbacks[this._callbackID++] = onSucc;
        }
    
        if (__DEV__) {
          global.nativeTraceBeginAsyncFlow &&
            global.nativeTraceBeginAsyncFlow(TRACE_TAG_REACT_APPS, 'native', this._callID);
        }
        this._callID++;
    
        //_queue是个队列,用来存放调用的模块、方法与参数信息。
        this._queue[MODULE_IDS].push(moduleID);
        this._queue[METHOD_IDS].push(methodID);
    
        if (__DEV__) {
          // Any params sent over the bridge should be encodable as JSON
          JSON.stringify(params);
    
          // The params object should not be mutated after being queued
          deepFreezeAndThrowOnMutationInDev((params:any));
        }
        this._queue[PARAMS].push(params);
    
        const now = new Date().getTime();
        //如果5ms内有多个方法调用则先待在队列里,防止过高频率的方法调用,否则则调用JSCExecutor::nativeFlushQueueImmediate(size_t argumentCount, const JSValueRef arguments[]) 方法。
        if (global.nativeFlushQueueImmediate &&
            now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS) {
          global.nativeFlushQueueImmediate(this._queue);
          this._queue = [[], [], [], this._callID];
          this._lastFlush = now;
        }
        Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length);
        if (__DEV__ && this.__spy && isFinite(moduleID)) {
          this.__spy(
            { type: TO_NATIVE,
              module: this._remoteModuleTable[moduleID],
              method: this._remoteMethodTable[moduleID][methodID],
              args: params }
          );
        } else if (this.__spy) {
          this.__spy({type: TO_NATIVE, module: moduleID + '', method: methodID, args: params});
        }
      }

    流程走到这个方法的时候,JS层的调用流程就结束了,JS层主要通过JSC桥接获取Java Module的注册表,并把它转换为对应的JS Native Module(属性、方法转换),当JS
    通过NativeModule.xxxMethod()准备调用Java方法时,会把xxxMethod()放进一个JS队列,在队列中:

    1 如果如果5m(MIN_TIME_BETWEEN_FLUSHES_MS)以内,则继续在队列中等待Java层的事件来驱动它。
    2 如果5m(MIN_TIME_BETWEEN_FLUSHES_MS)以内,则直接触发的 JSCExecutor::nativeFlushQueueImmediate(size_t argumentCount, const JSValueRef arguments[]) 方法去调用对应的Java方法。

    事实上,在队列中,如果是Java方法调用JS方法,则会把之前队列里存的方法通过JSCExecutor::flush()进行处理。

    我们再来看看JSCExecutor::nativeFlushQueueImmediate(size_t argumentCount, const JSValueRef arguments[]) 的实现。

    3.6 JSValueRef JSCExecutor::nativeFlushQueueImmediate(size_t argumentCount, const JSValueRef arguments[])

    JSCExecutor.cpp

    JSValueRef JSCExecutor::nativeFlushQueueImmediate(
        size_t argumentCount,
        const JSValueRef arguments[]) {
      if (argumentCount != 1) {
        throw std::invalid_argument("Got wrong number of args");
      }
    
      flushQueueImmediate(Value(m_context, arguments[0]));
      return Value::makeUndefined(m_context);
    }
    
    void JSCExecutor::flushQueueImmediate(Value&& queue) {
      auto queueStr = queue.toJSONString();
      //调用JsToNativeBridge.cpp的callNativeModules(),传入的isEndOfBatch=false
      m_delegate->callNativeModules(*this, folly::parseJson(queueStr), false);
    }

    可以看出nativeFlushQueueImmediate()会进一步调用flushQueueImmediate()方法,m_delegate的类型是ExecutorDelegate,事实上它调用的是ExecutorDelegate的子类
    JsToNativeBridge.cpp的callNativeModules()方法,我们回想一下上面我们分析Java代码调用JS代码第7步的实现,它也同样走到了这个方法,只是传入的isEndOfBatch=true。

    3.7 JsToNativeBridge::callNativeModules()

    JsToNativeBridge.cpp

      void callNativeModules()(
          JSExecutor& executor, folly::dynamic&& calls, bool isEndOfBatch) override {
    
        CHECK(m_registry || calls.empty()) <<
          "native module calls cannot be completed with no native modules";
        ExecutorToken token = m_nativeToJs->getTokenForExecutor(executor);
        //在Native队列中执行
        m_nativeQueue->runOnQueue([this, token, calls=std::move(calls), isEndOfBatch] () mutable {
    
          //遍历来自JS队列的调用方法列表
    
          // An exception anywhere in here stops processing of the batch.  This
          // was the behavior of the Android bridge, and since exception handling
          // terminates the whole bridge, there's not much point in continuing.
          for (auto& call : react::parseMethodCalls(std::move(calls))) {
            //m_registry的类型是ModuleRegistry,
            m_registry->callNativeMethod(
              token, call.moduleId, call.methodId, std::move(call.arguments), call.callId);
          }
          if (isEndOfBatch) {
            //标记回调Java状态
            m_callback->onBatchComplete();
            m_callback->decrementPendingJSCalls();
          }
        });
      }

    在该方法中取出JS队列中的JS调用Java的所有方法,并通过ModuleRegistry::callNativeMethod()方法去遍历调用,我们来看看这个方法的实现。

    3.8 ModuleRegistry::callNativeMethod(ExecutorToken token, unsigned int moduleId, unsigned int methodId, folly::dynamic&& params, int callId)

    void ModuleRegistry::callNativeMethod(ExecutorToken token, unsigned int moduleId, unsigned int methodId,
                                          folly::dynamic&& params, int callId) {
      if (moduleId >= modules_.size()) {
        throw std::runtime_error(
          folly::to<std::string>("moduleId ", moduleId,
                                 " out of range [0..", modules_.size(), ")"));
      }
    
    #ifdef WITH_FBSYSTRACE
      if (callId != -1) {
        fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId);
      }
    #endif
    
      //modules_是创建ModuleRegistryHolder时根据Java层ModuleRegistryHolder创建的C++ NativeModule
      //moduleId为模块在当前列表的索引值
      modules_[moduleId]->invoke(token, methodId, std::move(params));
    }

    modules_的类型是std::vector> modules_,NativeModule是C++层针对Java Module的一种包装,NativeModule的子类是JavaNativeModule,
    我们去看看它的调用方法invoke().

    3.9 JavaNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params)

    抽象类NativeModule定义的纯虚函数(抽象方法)

    NativeModule.cpp

    class NativeModule {
     public:
      virtual ~NativeModule() {}
      virtual std::string getName() = 0;
      virtual std::vector<MethodDescriptor> getMethods() = 0;
      virtual folly::dynamic getConstants() = 0;
      virtual bool supportsWebWorkers() = 0;
      // TODO mhorowitz: do we need initialize()/onCatalystInstanceDestroy() in C++
      // or only Java?
      virtual void invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) = 0;
      virtual MethodCallResult callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& args) = 0;
    };
    
    }
    }

    NativeModule有2个子类,它的类图如下所示:

    class JavaNativeModule : public NativeModule {
    
      void JavaNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {
    
      //wrapper_-的类型是JavaModuleWrapper.cpp,映射Java层的JavaModuleWrapper.java,在ModuleRegistryHolder.cpp构造方法中由Java传入的Java Module被C++包装成
      //JavaModuleWrapper对象。通过反射调用Java层的JavaModuleWrapper.java的invoke()方法,同时把mothodId和参数传过去。
      static auto invokeMethod =
        wrapper_->getClass()->getMethod<void(JExecutorToken::javaobject, jint, ReadableNativeArray::javaobject)>("invoke");
      invokeMethod(wrapper_, JExecutorToken::extractJavaPartFromToken(token).get(), static_cast<jint>(reactMethodId),
                   ReadableNativeArray::newObjectCxxArgs(std::move(params)).get());
    }
    }

    该方法调用通过反射调用Java层的JavaModuleWrapper.java的invoke()方法,同时把mothodId和参数传过去。我们来看看JavaModuleWrapper.java的invoke()方法的实现。

    3.10 JavaModuleWrapper.invoke(ExecutorToken token, int methodId, ReadableNativeArray parameters)

    
    //NativeModules是一个接口,我们知道要实现供JS调用的Java API我们需要编写类继承BaseJavaModule/ReactContextBaseJavaModule,BaseJavaModule/ReactContextBaseJavaModule就
    //实现了NativeModule接口,
     private final ArrayList<NativeModule.NativeMethod> mMethods;
    
    @DoNotStrip
    public class JavaModuleWrapper {
      @DoNotStrip
      public void invoke(ExecutorToken token, int methodId, ReadableNativeArray parameters) {
        if (mMethods == null || methodId >= mMethods.size()) {
          return;
        }
        //mMethods为所有继承BaseJavaModule类的BaseJavaModule.JavaMethod对象,也就是被ReactMethod注解标记的方法。
        mMethods.get(methodId).invoke(mJSInstance, token, parameters);
      }
    }

    JavaModuleWrapper对应C++层的NativeModule,该类针对Java BaseJavaModule进行了包装,是的C++层可以更加方便的通过JNI调用Java Module。

    四 Java层调用JS层

    RN应用通信机制流程图(Java->JS)如下所示:

    举例

    在文章ReactNative源码篇:启动流程中,我们在ReactInstanceManager.onAttachedToReactInstance()方法中调用APPRegistry.jS的runApplication()来
    启动RN应用,这就是一个典型的Java层调用JS层的例子,我们来具体分析一下这个例子的实现方式。

    1 首先定义了接口AppRegistry,该接口继承于JavaScriptModule,如下所示:

    /**
     * JS module interface - main entry point for launching React application for a given key.
     */
    public interface AppRegistry extends JavaScriptModule {
    
      void runApplication(String appKey, WritableMap appParameters);
      void unmountApplicationComponentAtRootTag(int rootNodeTag);
      void startHeadlessTask(int taskId, String taskKey, WritableMap data);
    }

    2 然后在CoreModulesPackage.createJSModules()将它添加到JavaScriptModule列表中,这个列表最终会被添加到JavaScriptModuleRegistry中。

    class CoreModulesPackage extends LazyReactPackage implements ReactPackageLogger {
    
      @Override
      public List<Class<? extends JavaScriptModule>> createJSModules() {
        List<Class<? extends JavaScriptModule>> jsModules = new ArrayList<>(Arrays.asList(
            DeviceEventManagerModule.RCTDeviceEventEmitter.class,
            JSTimersExecution.class,
            RCTEventEmitter.class,
            RCTNativeAppEventEmitter.class,
            AppRegistry.class,
            com.facebook.react.bridge.Systrace.class,
            HMRClient.class));
    
        if (ReactBuildConfig.DEBUG) {
          jsModules.add(DebugComponentOwnershipModule.RCTDebugComponentOwnership.class);
          jsModules.add(JSCHeapCapture.HeapCapture.class);
          jsModules.add(JSCSamplingProfiler.SamplingProfiler.class);
        }
    
        return jsModules;
      }
    }

    3 通过Java层调用AppRegistry.js的runApplication()方法,如下所示:

    //启动流程入口:由Java层调用启动
    catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);

    Java层调用JS层实现流程:

    Java层

    1 把要实现的功能编写成接口并继承JavaScriptModule,并交由ReactPackage管理,最终会在RN初始化的时候添加到JavaScriptModuleRegistry注册表中。
    2 通过ReactContext或者CatalystInstanceImpl获取JavaScriptModule,它们最终会通过JavaScriptModuleRegistry.getJavaScriptModule()获取对应的JavaScriptModule。
    3 JavaScriptModuleRegistry通过动态代理生成对应的JavaScriptModule,然后通过invoke()调用相应的JS方法,该方法会进一步去调用CatalystInstanceImpl.callJSFunction()
    该方法会调用native方法CatalystInstanceImpl.jniCallJSFunction()方法将相关参数传递到C++层,至此,整个流程便转入C++层。

    C++层

    4 CatalystInstanceImpl在C++层对应的是类CatalystInstanceImpl.cpp。CatalystInstanceImpl.cpp是RN针对Android平台的包装类,具体功能由Instance.cpp来完成,
    即Instance.cpp的callJSFunction()方法。
    5 Instance.cpp的callJSFunction()方法按照调用链:Instance.callJSFunction()->NativeToJsBridge.callFunction()->JSCExecutor.callFunction()最终将
    功能交由JSCExecutor.cpp的callFunction()方法来完成。
    6 JSCExecutor.cpp的callFunction()方法通过Webkit JSC调用JS层的MessageQueue.js里的callFunctionReturnFlushedQueue()方法,自此整个流程转入JavaScript层。

    JS层

    7 MessageQueue.js里的callFunctionReturnFlushedQueue()方法,该方法按照调用链:MessageQueue.callFunctionReturnFlushedQueue()->MessageQueue.__callFunction()
    在JS层里的JavaScriptModule注册表里产找对应的JavaScriptModule及方法。

    我们来分析上述代码的调用方式。

    可以看出AppRegistry继承于JavaScriptModule,AppRegistry作为核心逻辑之一被添加到CoreModulesPackage中,我们知道在ReactInstanceManager.createReactContext()方法
    中,CoreModulesPackage作为ReactPackage被添加进了JavaScriptModuleRegistry中,JavaScriptModuleRegistry被CatalystInstanceImpl来管理。

    所以才有了Java层调用JS层代码的通用格式:

    CatalystInstanceImpl.getJSModule(xxx.class).method(params, params, ...);

    当然,如果使我们调用自己的JS Module,我们是用ReactContext.getJSModule(),因为ReactContext持有CatalystInstanceImpl的实例,CatalystInstanceImpl并不直接对外公开。

    Java层代码调用JS层代码,需要将JavaScriptModule注册到JavaScriptModuleRegistry中,然后通过动态代理获取方法的各种参数,再将参数通过参数通过C++层传递到JS层从而完成调用,我们
    先来看看CatalystInstanceImpl是如何拿到JavaScriptModule的。

    CatalystInstanceImpl.getJSModule()调用JavaScriptModuleRegistry.getJavaScriptModule()去查询JavaScriptModule。

    4.1 JavaScriptModuleRegistry.getJavaScriptModule(CatalystInstance instance, ExecutorToken executorToken, Class moduleInterface)

    它的实现如下所示:

    public class JavaScriptModuleRegistry {
    
      public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
        CatalystInstance instance,
        ExecutorToken executorToken,
        Class<T> moduleInterface) {
    
        //如果JavaScriptModule加载一次,就保存在缓存中,第二次加载时直接从缓存中取。
        HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> instancesForContext =
            mModuleInstances.get(executorToken);
        if (instancesForContext == null) {
          instancesForContext = new HashMap<>();
          mModuleInstances.put(executorToken, instancesForContext);
        }
        JavaScriptModule module = instancesForContext.get(moduleInterface);
        if (module != null) {
          return (T) module;
        }
    
        //利用动态代理获取JavaScriptModule对象
    
        //JavaScriptModuleRegistration是对JavaScriptModule的包装,检查实现JavaScriptModule接口的类是否存在重载,因为JS不支持重载。
        JavaScriptModuleRegistration registration =
            Assertions.assertNotNull(
                mModuleRegistrations.get(moduleInterface),
                "JS module " + moduleInterface.getSimpleName() + " hasn't been registered!");
        JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
            moduleInterface.getClassLoader(),
            new Class[]{moduleInterface},
            new JavaScriptModuleInvocationHandler(executorToken, instance, registration));
        instancesForContext.put(moduleInterface, interfaceProxy);
        return (T) interfaceProxy;
      }
    
      private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
    
        private final WeakReference<ExecutorToken> mExecutorToken;
        private final CatalystInstance mCatalystInstance;
        private final JavaScriptModuleRegistration mModuleRegistration;
    
        public JavaScriptModuleInvocationHandler(
            ExecutorToken executorToken,
            CatalystInstance catalystInstance,
            JavaScriptModuleRegistration moduleRegistration) {
          mExecutorToken = new WeakReference<>(executorToken);
          mCatalystInstance = catalystInstance;
          mModuleRegistration = moduleRegistration;
        }
    
        @Override
        public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
          ExecutorToken executorToken = mExecutorToken.get();
          if (executorToken == null) {
            FLog.w(ReactConstants.TAG, "Dropping JS call, ExecutorToken went away...");
            return null;
          }
          NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
          //调用CatalystInstanceImpl.callFunction()方法。
          mCatalystInstance.callFunction()方法。(
            executorToken,
            mModuleRegistration.getName(),
            method.getName(),
            jsArgs
          );
          return null;
        }
      }
    }

    可以看出,在JavaScriptModuleRegistry通过动态代理的方式获取JavaScriptModule,对Java动态代理不熟悉的同学,这里我们先简单回忆一下Java动态代理相关内容。

    Java动态代理

    Java动态代理主要涉及两个类:
    
    java.lang.reflect.Proxy:用来生成代理类。
    java.lang.reflect.InvocationHandler:调用处理器,我们需要自己定义一个类来指定动态生成的代理类需要完成的具体内容。
    
    Proxy的主要方法:
    
    static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler)//创建代理对象  
    
    ClassLoader loader:类加载器,指定使用哪个类加载器将代理类加载到JVM的方法区。
    Class<?>[] interfaces:代理类需要实现的接口。
    InvocationHandler handler:调用处理器实例,指定代理类具体要做什么。
    
    实现Java动态代理需要以下3步:
    
    1 定义一个委托类和公共接口。
    2 定义调用处理器类实现InvocationHandler接口,指定代理类具体要完成的任务。
    3 生成代理对象
    
    一个代理对象对应一个委托类对应一个调用处理器类

    JavaScriptModuleInvocationHandler.invoke()方法获取了moduleID,methodID,并去调用CatalystInstanceImpl.callFunction();

    4.2 CatalystInstanceImpl.callFunction(ExecutorToken executorToken, final String module, final String method, final NativeArray arguments)

    
    public class CatalystInstanceImpl{
    
      @Override
      public void callFunction(
          ExecutorToken executorToken,
          final String module,
          final String method,
          final NativeArray arguments) {
        if (mDestroyed) {
          FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
          return;
        }
        if (!mAcceptCalls) {
          // Most of the time the instance is initialized and we don't need to acquire the lock
          synchronized (mJSCallsPendingInitLock) {
            if (!mAcceptCalls) {
              mJSCallsPendingInit.add(new PendingJSCall(executorToken, module, method, arguments));
              return;
            }
          }
        }
    
        jniCallJSFunction(executorToken, module, method, arguments);
      }
    
      private native void jniCallJSCallback(ExecutorToken executorToken, int callbackID, NativeArray arguments);
    }

    方法走到这里,实现逻辑已经由Java层转到C++层,我们去C++层看看具体的实现。

    CatalystInstanceImpl.java在C++层有个对应的类CatalystInstanceImpl.cpp。

    4.3 CatalystInstanceImpl.jniCallJSFunction(JExecutorToken token, std::string module, std::string method, NativeArray arguments)

    CatalystInstanceImpl.cpp

    void CatalystInstanceImpl::jniCallJSFunction(
    
        JExecutorToken* token, std::string module, std::string method, NativeArray* arguments) {
      // We want to share the C++ code, and on iOS, modules pass module/method
      // names as strings all the way through to JS, and there's no way to do
      // string -> id mapping on the objc side.  So on Android, we convert the
      // number to a string, here which gets passed as-is to JS.  There, they they
      // used as ids if isFinite(), which handles this case, and looked up as
      // strings otherwise.  Eventually, we'll probably want to modify the stack
      // from the JS proxy through here to use strings, too.
      instance_->callJSFunction(token->getExecutorToken(nullptr),
                                std::move(module),
                                std::move(method),
                                arguments->consume());
    }

    可以发现CatalystInstanceImpl.cpp的jniCallJSFunction()方法又会去调用Instance.cpp里的callJSFunction()方法,其实CatalystInstanceImpl.cpp只是RN针对
    Android平台适配的封装,主要做了写参数类型转换,本质上它对应了ReactCommon包里的Instance.cpp,真正的实现在Instance.cpp中完成。我们来看一看Instance.cpp中的实现。

    4.4 Instance.callJSFunction(ExecutorToken token, std::string&& module, std::string&& method, folly::dynamic&& params)

    Instance.cpp

    void Instance::callJSFunction(ExecutorToken token, std::string&& module, std::string&& method,
                                  folly::dynamic&& params) {
      callback_->incrementPendingJSCalls();
      nativeToJsBridge_->callFunction(token, std::move(module), std::move(method), std::move(params));
    }

    Instance.cpp的callJSFunction()进一步去调用NativeToJsBridge.cpp的callFunction()方法,我们来看看它的实现。

    4.5 NativeToJsBridge.callFunction(ExecutorToken executorToken, std::string&& module, std::string&& method, folly::dynamic&& arguments)

    NativeToJsBridge.cpp

    void NativeToJsBridge::callFunction(
        ExecutorToken executorToken,
        std::string&& module,
        std::string&& method,
        folly::dynamic&& arguments) {
    
      int systraceCookie = -1;
      #ifdef WITH_FBSYSTRACE
      systraceCookie = m_systraceCookie++;
      std::string tracingName = fbsystrace_is_tracing(TRACE_TAG_REACT_CXX_BRIDGE) ?
        folly::to<std::string>("JSCall__", module, '_', method) : std::string();
      SystraceSection s(tracingName.c_str());
      FbSystraceAsyncFlow::begin(
          TRACE_TAG_REACT_CXX_BRIDGE,
          tracingName.c_str(),
          systraceCookie);
      #else
      std::string tracingName;
      #endif
    
      runOnExecutorQueue(executorToken, [module = std::move(module), method = std::move(method), arguments = std::move(arguments), tracingName = std::move(tracingName), systraceCookie] (JSExecutor* executor) {
        #ifdef WITH_FBSYSTRACE
        FbSystraceAsyncFlow::end(
            TRACE_TAG_REACT_CXX_BRIDGE,
            tracingName.c_str(),
            systraceCookie);
        SystraceSection s(tracingName.c_str());
        #endif
    
        //调用JSCExecutor.cppd的callFunction()
        // This is safe because we are running on the executor's thread: it won't
        // destruct until after it's been unregistered (which we check above) and
        // that will happen on this thread
        executor->callFunction(module, method, arguments);
      });
    }

    NativeToJsBridge.cpp的callFunction()进一步去调用JSCExecutor.cppd的callFunction()方法,我们来看看它的实现。

    4.6 JSCExecutor.callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments)

    JSCExecutor.cpp

    void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {
      SystraceSection s("JSCExecutor::callFunction");
      // This weird pattern is because Value is not default constructible.
      // The lambda is inlined, so there's no overhead.
    
      auto result = [&] {
        try {
          // See flush()
          CHECK(m_callFunctionReturnFlushedQueueJS)
            << "Attempting to call native methods without loading BatchedBridge.js";
          return m_callFunctionReturnFlushedQueueJS->callAsFunction({
            Value(m_context, String::createExpectingAscii(m_context, moduleId)),
            Value(m_context, String::createExpectingAscii(m_context, methodId)),
            Value::fromDynamic(m_context, std::move(arguments))
          });
        } catch (...) {
          std::throw_with_nested(
            std::runtime_error("Error calling " + moduleId + "." + methodId));
        }
      }();
    
      //将调用结果返回给Java层
      callNativeModules(std::move(result));
    }

    可以看出,该函数进一步调用m_callFunctionReturnFlushedQueueJS->callAsFunction(),我们先来解释下m_callFunctionReturnFlushedQueueJS这个变量的由来,它在JSCExecutor::bindBridge()里
    初始化,本质上就是通过Webkit JSC拿到JS层代码相关对象和方法引用,m_callFunctionReturnFlushedQueueJS就是MessageQueue.js里的callFunctionReturnFlushedQueue()方法的引用。

    void JSCExecutor::bindBridge() throw(JSException) {
    
      ...
    
     m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
    
      ...
    }

    4.7 MessageQueue.callFunctionReturnFlushedQueue(module: string, method: string, args: Array)

    MessageQueue.callFunctionReturnFlushedQueue()方法的实现如下所示:

    MessageQueue.js

      callFunctionReturnFlushedQueue(module: string, method: string, args: Array<any>) {
        guard(() => {
          this.__callFunction(module, method, args);
          this.__callImmediates();
        });
    
        return this.flushedQueue();
      }
    
      __callFunction(module: string, method: string, args: Array<any>) {
        this._lastFlush = new Date().getTime();
        this._eventLoopStartTime = this._lastFlush;
        Systrace.beginEvent(`${module}.${method}()`);
        if (this.__spy) {
          this.__spy({ type: TO_JS, module, method, args});
        }
    
        //从JS层的JavaScriptModule注册表中查找到AppRegistry.js
        const moduleMethods = this._callableModules[module];
        invariant(
          !!moduleMethods,
          'Module %s is not a registered callable module (calling %s)',
          module, method
        );
        invariant(
          !!moduleMethods[method],
          'Method %s does not exist on module %s',
          method, module
        );
        //取到Java层调用的JS层方法,例如:AppRegistry.js的runApplication()方法
        const result = moduleMethods[method].apply(moduleMethods, args);
        Systrace.endEvent();
        return result;
      }

    从JS层的JavaScriptModule注册表中查找到AppRegistry.js,最终调用AppRegistry.js的runApplication()方法。

    好,以上就是Java层代码调用JS层代码的全部流程,我们再来总结一下:

    Java层

    1 把要实现的功能编写成接口并继承JavaScriptModule,并交由ReactPackage管理,最终会在RN初始化的时候添加到JavaScriptModuleRegistry注册表中。
    2 通过ReactContext或者CatalystInstanceImpl获取JavaScriptModule,它们最终会通过JavaScriptModuleRegistry.getJavaScriptModule()获取对应的JavaScriptModule。
    3 JavaScriptModuleRegistry通过动态代理生成对应的JavaScriptModule,然后通过invoke()调用相应的JS方法,该方法会进一步去调用CatalystInstanceImpl.callJSFunction()
    该方法会调用native方法CatalystInstanceImpl.jniCallJSFunction()方法将相关参数传递到C++层,至此,整个流程便转入C++层。

    C++层

    4 CatalystInstanceImpl在C++层对应的是类CatalystInstanceImpl.cpp。CatalystInstanceImpl.cpp是RN针对Android平台的包装类,具体功能由Instance.cpp来完成,
    即Instance.cpp的callJSFunction()方法。
    5 Instance.cpp的callJSFunction()方法按照调用链:Instance.callJSFunction()->NativeToJsBridge.callFunction()->JSCExecutor.callFunction()最终将
    功能交由JSCExecutor.cpp的callFunction()方法来完成。
    6 JSCExecutor.cpp的callFunction()方法通过Webkit JSC调用JS层的MessageQueue.js里的callFunctionReturnFlushedQueue()方法,自此整个流程转入JavaScript层。

    JavaScript层

    7 MessageQueue.js里的callFunctionReturnFlushedQueue()方法,该方法按照调用链:MessageQueue.callFunctionReturnFlushedQueue()->MessageQueue.__callFunction()
    在JS层里的JavaScriptModule注册表里产找对应的JavaScriptModule及方法。
    展开全文
  • 当前分析的ReactNative版本为0.61.5: 看这边文章前最好先了解UIManagerModule、...1.ReactNative源码分析之UIManagerModule. 2.ReactNative源码分析之UIViewOperationQueue. 3.ReactNative源码分析之UIImplementat...

    当前分析的ReactNative版本为0.61.5:

    看这边文章前最好先了解UIManagerModule、UIImplementation、UIViewOperationQueue类;

    1.ReactNative源码分析之UIManagerModule.
    2.ReactNative源码分析之UIViewOperationQueue.
    3.ReactNative源码分析之UIImplementation.

    我们看NativeViewHierarchyManager的名字就知道,它其实是一个管理类,管理所有的View。

    先来看下它的私有字段:

      private final SparseArray<View> mTagsToViews;
      private final SparseArray<ViewManager> mTagsToViewManagers;
      private final ViewManagerRegistry mViewManagers;
    

    从这几个字段我们就能猜测,它管理着所有的ViewManager和对应的View,映射关系是通过int值关联,这个int值其实就是ViewTag。

    我们找几个方法看看具体实现:

      public final synchronized View resolveView(int tag) {
        View view = mTagsToViews.get(tag);
        if (view == null) {
          throw new IllegalViewOperationException(
              "Trying to resolve view with tag " + tag + " which doesn't exist");
        }
        return view;
      }
    
    

    这个是根据ViewTag,查找对应的View。

      public final synchronized ViewManager resolveViewManager(int tag) {
        ViewManager viewManager = mTagsToViewManagers.get(tag);
        if (viewManager == null) {
          boolean alreadyDropped = Arrays.asList(mDroppedViewArray).contains(tag);
          throw new IllegalViewOperationException(
              "ViewManager for tag "
                  + tag
                  + " could not be found.\n View already dropped? "
                  + alreadyDropped
                  + ".\nLast index "
                  + mDroppedViewIndex
                  + " in last 100 views"
                  + mDroppedViewArray.toString());
        }
        return viewManager;
      }
    

    这个是通过ViewTag,查找对应的ViewManager。

    在之前的文章提到UIViewOperationQueue类,所有对View的UI操作本质上是由NativeViewHierarchyManager代理执行,想操作哪个View,那就传入该View的ViewTag。

    通过NativeViewHierarchyManager管理的ViewTag、View,ViewManager映射关系,最终直接操作到View和ViewManager相应的方法上。

    举个例子,创建View:

    public synchronized void createView(
          ThemedReactContext themedContext,
          int tag,
          String className,
          @Nullable ReactStylesDiffMap initialProps) {
        UiThreadUtil.assertOnUiThread();
        SystraceMessage.beginSection(
                Systrace.TRACE_TAG_REACT_VIEW, "NativeViewHierarchyManager_createView")
            .arg("tag", tag)
            .arg("className", className)
            .flush();
        try {
          ViewManager viewManager = mViewManagers.get(className);
    
          View view = viewManager.createView(themedContext, null, null, mJSResponderHandler);
          mTagsToViews.put(tag, view);
          mTagsToViewManagers.put(tag, viewManager);
    
          Log.i(TAG, "createView tag:"+tag + " view:"+view.getClass().getSimpleName() + " count:"+mTagsToViews.size());
    
          // Use android View id field to store React tag. This is possible since we don't inflate
          // React views from layout xmls. Thus it is easier to just reuse that field instead of
          // creating another (potentially much more expensive) mapping from view to React tag
          view.setId(tag);
          if (initialProps != null) {
            viewManager.updateProperties(view, initialProps);
          }
        } finally {
          Systrace.endSection(Systrace.TRACE_TAG_REACT_VIEW);
        }
      }
    

    通过tag,查找对应的ViewManager,通过ViewManager创建View,初始化View属性,最后将View保存到tag和View、ViewManager映射关系中,最后返回。

    再来看看更新View属性的代码:

      public synchronized void updateProperties(int tag, ReactStylesDiffMap props) {
        UiThreadUtil.assertOnUiThread();
    
        try {
    
          ViewManager viewManager = resolveViewManager(tag);
          View viewToUpdate = resolveView(tag);
          if (props != null) {
            viewManager.updateProperties(viewToUpdate, props);
          }
        } catch (IllegalViewOperationException e) {
          FLog.e(TAG, "Unable to update properties for view tag " + tag, e);
        }
      }
    

    通过tag,查找对应的ViewManager和View,再通过这两个类更新其属性。

    再来看看更新View的Layout:

    public synchronized void updateLayout(
          int parentTag, int tag, int x, int y, int width, int height) {
        UiThreadUtil.assertOnUiThread();
        SystraceMessage.beginSection(
                Systrace.TRACE_TAG_REACT_VIEW, "NativeViewHierarchyManager_updateLayout")
            .arg("parentTag", parentTag)
            .arg("tag", tag)
            .flush();
        try {
          View viewToUpdate = resolveView(tag);
    
          Log.i(TAG,"updateLayout tag:"+viewToUpdate.getId() + " viewName:"+viewToUpdate.getClass().getSimpleName() + " x:"+x + " y:"+y + " width:"+width + " height:"+height);
    
    
          // Even though we have exact dimensions, we still call measure because some platform views
          // (e.g.
          // Switch) assume that method will always be called before onLayout and onDraw. They use it to
          // calculate and cache information used in the draw pass. For most views, onMeasure can be
          // stubbed out to only call setMeasuredDimensions. For ViewGroups, onLayout should be stubbed
          // out to not recursively call layout on its children: React Native already handles doing
          // that.
          //
          // Also, note measure and layout need to be called *after* all View properties have been
          // updated
          // because of caching and calculation that may occur in onMeasure and onLayout. Layout
          // operations should also follow the native view hierarchy and go top to bottom for
          // consistency
          // with standard layout passes (some views may depend on this).
    
          viewToUpdate.measure(
              View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
              View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
    
          // We update the layout of the ReactRootView when there is a change in the layout of its
          // child.
          // This is required to re-measure the size of the native View container (usually a
          // FrameLayout) that is configured with layout_height = WRAP_CONTENT or layout_width =
          // WRAP_CONTENT
          //
          // This code is going to be executed ONLY when there is a change in the size of the Root
          // View defined in the js side. Changes in the layout of inner views will not trigger an
          // update
          // on the layout of the Root View.
          ViewParent parent = viewToUpdate.getParent();
          if (parent instanceof RootView) {
            parent.requestLayout();
          }
    
          // Check if the parent of the view has to layout the view, or the child has to lay itself out.
          if (!mRootTags.get(parentTag)) {
            ViewManager parentViewManager = mTagsToViewManagers.get(parentTag);
            IViewManagerWithChildren parentViewManagerWithChildren;
            if (parentViewManager instanceof IViewManagerWithChildren) {
              parentViewManagerWithChildren = (IViewManagerWithChildren) parentViewManager;
            } else {
              throw new IllegalViewOperationException(
                  "Trying to use view with tag "
                      + parentTag
                      + " as a parent, but its Manager doesn't implement IViewManagerWithChildren");
            }
            if (parentViewManagerWithChildren != null
                && !parentViewManagerWithChildren.needsCustomLayoutForChildren()) {
              updateLayout(viewToUpdate, x, y, width, height);
            }
          } else {
            updateLayout(viewToUpdate, x, y, width, height);
          }
        } finally {
          Systrace.endSection(Systrace.TRACE_TAG_REACT_VIEW);
        }
      }
    
      private void updateLayout(View viewToUpdate, int x, int y, int width, int height) {
        if (mLayoutAnimationEnabled && mLayoutAnimator.shouldAnimateLayout(viewToUpdate)) {
          mLayoutAnimator.applyLayoutUpdate(viewToUpdate, x, y, width, height);
        } else {
          viewToUpdate.layout(x, y, x + width, y + height);
        }
      }
    

    我们看到,核心逻辑就是先通过tag,查找对应的View,然后直接操作View的layout方法。

    其他数对UI操作的方法都是如此,总结如下:
    1.通过tag查找对应的View和ViewManager;
    2.根据相应的方法,操作对应的View和ViewManager;
    3.最后需要注意,所有的操作都需要在UI线程中执行;

    展开全文
  • 在开始《ReactNative源码解析》系列文章之前,我们先不对源码做深入的分析,我们先对源码的结构和ReactNative的框架做个简要的分析和了解,我们将围绕它的核心进行展开。 1. ReactNative框架是怎样的? 2. React...

    在开始《ReactNative源码解析》系列文章之前,我们先不对源码做深入的分析,我们先对源码的结构和ReactNative的框架做个简要的分析和了解,我们将围绕它的核心进行展开。

    1. ReactNative框架是怎样的?
    2. ReactNative框架的核心是什么,如何去分析?
    复制代码

    好,我们先来看第一个问题。

    一、ReactNative框架总览

    ReactNative源码结构如下:

    - jni:ReactNative的核心机制都是由C、C++实现的,这部分便是用来载入SO库。
    - perftest:测试配置
    - proguard:混淆
    - react:ReactNative Java层源码部分,我们将对这些源码进行重点分析。
    - systrace:system trace
    - yoga:facebook开源跨平台的布局引擎
    复制代码

    ReactNative系统框架图如下所示:

    二、ReactNative框架的核心

    通过对ReactNative系统框架的分析,我们可以发现源码的核心如下:

    1、ReactNative启动流程
    2、ReactNativeUI渲染
    3、ReactNative通信机制(Java调用JS,JS调用Java)
    4、ReactNative事件处理
    5、ReactNative线程模型
    复制代码

    后面的文章将按照此顺序对ReactNative框架展开深入分析,在分析之前,我们先来理解一下关于ReactNative的重要概念。

    三 ReactNative框架的重要概念

    1、ReactContext

    ReactContext继承于ContextWrapper,是ReactNative应用的上下文;可以简单理解它和Android中的Context是一个概念,是整个应用的上下文。
    复制代码

    从类图中可以看出继承关系,有没有发现和Android中的context继承关系很像呢?应了那句话,好的设计总是相似的。
    2、ReactInstanceManager

    ReactInstanceManager是ReactNative应用总的管理类,创建ReactContext、CatalystInstance等类,解析ReactPackage生成映射表,并且配合ReactRootView管理View的创建与生命周期等功能。
    复制代码

    3、CatalystInstance

    CatalystInstance是ReactNative应用Java层、C++层、JS层通信总管理类,总管Java层、JS层核心Module映射表与回调,三端通信的入口与桥梁。
    
    复制代码

    4、NativeToJsBridge/JsToNativeBridge

    NativeToJsBridge是Java调用JS的桥梁,用来调用JS Module,回调Java。
    JsToNativeBridge是JS调用Java的桥梁,用来调用Java Module。
    复制代码

    5、JavaScriptModule/NativeModule

    JavaScriptModule是JS Module,负责JS到Java的映射调用格式声明,由CatalystInstance统一管理。
    NativeModule是ava Module,负责Java到Js的映射调用格式声明,由CatalystInstance统一管理。
    JavaScriptModule:JS暴露给Java调用的API集合,例如:AppRegistry、DeviceEventEmitter等。业务放可以通过继承JavaScriptModule接口类似自定义接口模块,声明 与JS相对应的方法即可。
    NativeModule/UIManagerModule:NativeModule是Java暴露给JS调用的APU集合,例如:ToastModule、DialogModule等,UIManagerModule也是供JS调用的API集 合,它用来创建View。业务放可以通过实现NativeModule来自定义模块,通过getName()将模块名暴露给JS层,通过@ReactMethod注解将API暴露给JS层。 
    复制代码

    6、JavascriptModuleRegistry

    JavascriptModuleRegistry是JS Module映射表,NativeModuleRegistry是Java Module映射表
    复制代码

    转载于:https://juejin.im/post/5cd70261f265da03b446301b

    展开全文
  • 此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React Native 源码学习方法及其他资源。 此文是我的出版书籍《React Native 精解与实战》连载分享,此书由机械工业出版社出版,...
  • 当前分析的ReactNative版本为...1.ReactNative源码分析之UIManagerModule. 2.ReactNative源码分析之UIImplementation. 从UIViewOperationQueue名称可知,首先该类是一个操作UIView为主,同时具有缓存功能的这样一...
  • ReactNative源码分析之UIManagerModule. 我们提到,UIManagerModule本身是个NativeModule,它通过各种ReactMethod注解方法,提供JS直接调用,大多数方法直接由UIImplementation代理。 我们看下UIImplementati...
  • React Native 源码浅析

    2017-07-05 21:31:18
    React Native 源码浅析 1.RN是如何完成bundle文件加载的? 2.Native和JS之间是如何通讯的? 3.JS布局是怎么样被渲染到ReactRootView上的? 下面通过对RN源码(版本:0.40.0)的分析,尝试找找这3个问题的答案~ ...
  • ReactNative源码分析之NativeModule调用堆栈分析. 这篇文章分析的最后,涉及到Callback分析。 NativeModule提供的方法,如果想把方法返回的结果传回给JS层,那么实现有两种方式,一种是通过Callback,一种是Promise...
  • 运行React Native源码中的例子
  • ReactNative 源码编译集成

    千次阅读 2018-04-06 00:32:24
    尝试将ReactNative源码编译并在Android手机上运行一个HelloWorld, 浪费不少时间踩坑,总结一下整个搭建过程:   1. 准备工作: Android SDK 26.0.1 Android NDK android-ndk-r...
  • 当前分析的ReactNative版本为0.61.5: 一、NativeModule基本使用 我们知道,要想访问原生提供的功能,需要通过继承NativeModule,并提供相关的方法,只有这样JS层才能直接访问。 举个例子,StatusBarModule类: /** {...
  • 关于作者 郭孝星,程序员,吉他手,主要从事Android平台基础架构方面的工作,欢迎交流技术方面...本篇系列文章主要分析ReactNative源码,分析ReactNative的启动流程、渲染原理、通信机制与线程模型等方面内容。 ...
  • ReactNative源码篇:渲染原理

    千次阅读 2017-09-02 15:31:52
    ReactNative源码篇:渲染原理关于作者 郭孝星,非著名程序员,主要从事Android平台基础架构与中间件方面的工作,欢迎交流技术方面的问题,可以去我的Github提交Issue或者发邮件至guoxiaoxingse@163.com与我联系。 ...
  • ReactNative用的版本: 0.61.5 原生层事件的触发入口主要有两个类: 1. ReactRootView 2. 自定义的ViewManager对应的viewGroup 今天我们主要梳理ReactRootView事件传递 一、ReactRootView JavaScript中加载的View...
  • 在上一节中,我们通过一个相册的制作来学习了React Native...这一节我们需要开始学习React Native源码。 学习源码,从编译源码开始。 首先,我们需要把代码从github中克隆下来。 https://github.com/faceb
  • 当前分析的ReactNative版本为:0.61.5: ReactNative中最核心的当属ReactContext,想访问ReactNative框架相关类,第一个需要的就是ReactContext。 原生层定义NativeModule, 我们往往直接继承...
  • ReactNative是Facebook开源的一种实现移动跨平台开发的解决方案,目前在业界得到广泛应用,这里有非常详细的中文使用指南。本文主要分享RN源码中一些值得大家学习或者借鉴的代码...整个ReactNative源码工程中用到...
  • 当前分析的ReactNative版本为0.61.5: ReactNative中为了能访问原生功能模块,它提供了NativeModule接口,看下该接口的定义,实现比较简单,直接继承它的两个类分别是BaseJavaModule和CxxModuleWrapperBase。 从名字...
  • 当前分析的ReactNative版本为0.61.5: 今天的主角是UIManagerModule,我们看它的定义,本质上是个NativeModule,可以通过ReactContext访问。 先来看看它的私有变量mViewManagerRegistry,该类负责管理ViewManagerName...
  • 此文是我的出版书籍《React Native 精解与实战》连载分享,此书由机械工业出版社出版,书中详解了 React Native 框架底层原理、React Native 组件布局、组件与 API 的介绍与代码实战,以及 React Native 与 iOS、...
  • 当前分析的ReactNative版本为0.61.5: 一、ViewManager定义 首先我们来看ViewManager的定义: /** * Class responsible for knowing how to create and update catalyst Views of a given type. It is also * ...
  • 当前分析的ReactNative版本为0.61.5: 首先来看ReactRootView的定义: /** * Default root view for catalyst apps. Provides the ability to listen for size changes so that a UI * manager can re-layout its ...
  • ReactNative源码分析之VirtualizedList

    千次阅读 2018-01-02 16:36:55
    ReactNative列表是基于ScrollView的,并没有直接使用IOS或Android的原生列表组件。因为RN真正调用native代码是异步的,并不能保证同步,而在native环境中,所有即将在视窗中呈现的元素都必须同步渲染,超过一定的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,882
精华内容 1,552
关键字:

reactnative源码