美文网首页ReactNative
ReactNative Android源码分析

ReactNative Android源码分析

作者: 小草33 | 来源:发表于2017-02-13 00:06 被阅读0次

    这篇文章针对于对rn有些基础的同学,没有基础的同学可以先了解一下rn以后再看这篇文章。要想深入理解 React Native 的工作原理,有两个部分的源码需要阅读:rn的初始化和java与js通信的过程,首先分析rn的初始化过程。

    一、RN的初始化过程

    从官方rn的demo入手,看rn是如何一步步如何初始化的:

    public class MainActivity extends ReactActivity {
    
    /**
    
    *  用来返回要显示的js端的组件的名称,这个要和js端注册的Component名称一一对应。
    
    */
    
    @Override
    
    protected String getMainComponentName() {
    
    return "AwesomeProject";
    
    }
    }
    
    

    MainActivity继承于ReactActivity,ReactActivity是rn中页面显示的入口,负责页面的显示,下面就进入源码看它怎么实现的:
    进入ReactActivity的onCreate中发现ReactActivity只是一个空壳子,所有的逻辑都交给ReactActivityDelegate类实现,这是典型的代理模式,这样做的好处:1、实现和接口分开;2、可以在FragmentActivity也同样可以使用,不用维护两套逻辑。
    接着查看ReactActivityDelegate的onCreate方法,这个函数中最重要的逻辑就是loadApp方法:

    protected void loadApp(String appKey) {
       ...
        mReactRootView = createRootView();
        mReactRootView.startReactApplication(
          getReactNativeHost().getReactInstanceManager(),
          appKey,
          getLaunchOptions());
        getPlainActivity().setContentView(mReactRootView);
      }
    

    这个函数主要实现两个功能:
    1、创建ReactRootView,并将这个view设置为activity的根view。ReactRootView继承FrameLayout,它主要负责native端事件(键盘事件、touch事件、页面大小变化等)的监听并将结果传递给js端以及负责页面元素的重新绘制。
    2、调用ReactRootView的startReactApplication方来,来启动整个rn流。
    startReactApplication函数:

     public void startReactApplication(
          ReactInstanceManager reactInstanceManager,
          String moduleName,
          @Nullable Bundle launchOptions) {
        ...
        //rn的上下文没有创建
        if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
        //创建rn的上下文ReactContext对象
          mReactInstanceManager.createReactContextInBackground();
        }
        if (mWasMeasured) {
          attachToReactInstanceManager();
        }
      }
    

    由于是第一次调用,hasStartedCreatingInitialContext函数返回false,此时,进入mReactInstanceManager.createReactContextInBackground()函数,在分析这个函数之前,先介绍一下两个类:
    ReactInstanceManager,rn的java端的控制器,它主要的功能是创建和管理CatalystInstance实例并和ReactActivity的生命周期保持一致。
    CatalystInstance:jsc桥梁接口类,为java和js相互通信提供环境。
    进入createReactContextInBackground函数,发现函数最后会走到recreateReactContextInBackgroundInner()函数。

    recreateReactContextInBackgroundInner函数:

    private void recreateReactContextInBackgroundInner() {
        ...
         //是否使用开发者模式,默认情况下是true
        if (mUseDeveloperSupport && mJSMainModuleName != null) {
          final DeveloperSettings devSettings = mDevSupportManager.getDevSettings();
    
          // 本地bundle文件是最新的并且不开启远程js调试,用本地的bundle文件
          if (mDevSupportManager.hasUpToDateJSBundleInCache() &&
              !devSettings.isRemoteJSDebugEnabled()) {
            onJSBundleLoadedFromServer();
          } else if (mBundleLoader == null) {
            mDevSupportManager.handleReloadJS();
          } else {
          //调用okHttp下载bundle文件
            mDevSupportManager.isPackagerRunning(
                new DevServerHelper.PackagerStatusCallback() {
                  @Override
                  public void onPackagerStatusFetched(final boolean packagerIsRunning) {
                    UiThreadUtil.runOnUiThread(
                        new Runnable() {
                          @Override
                          public void run() {
                            if (packagerIsRunning) {
                              mDevSupportManager.handleReloadJS();
                            } else {
                            
                              devSettings.setRemoteJSDebugEnabled(false);
                              recreateReactContextInBackgroundFromBundleLoader();
                            }
                          }
                        });
                  }
                });
          }
          return;
        }
    
        recreateReactContextInBackgroundFromBundleLoader();
      }
    

    recreateReactContextInBackgroundFromBundleLoader函数:

    private void recreateReactContextInBackgroundFromBundleLoader() {
        recreateReactContextInBackground(
            new JSCJavaScriptExecutor.Factory(mJSCConfig.getConfigMap()),
            mBundleLoader);
      }
    

    JSCJavaScriptExecutor:是JavaScriptExecutor的子类,是js执行器。
    JSCJavaScriptExecutor.Factory:工厂模式,产生JSCJavaScriptExecutor实例。

    public class JSCJavaScriptExecutor extends JavaScriptExecutor {
      public static class Factory implements JavaScriptExecutor.Factory {
        private ReadableNativeArray mJSCConfig;
    
        public Factory(WritableNativeMap jscConfig) {
          array.pushMap(jscConfig);
          mJSCConfig = array;
        }
    
       //创建JSCJavaScriptExecutor实例
        @Override
        public JavaScriptExecutor create() throws Exception {
          return new JSCJavaScriptExecutor(mJSCConfig);
        }
      }
    
      public JSCJavaScriptExecutor(ReadableNativeArray jscConfig) {
        super(initHybrid(jscConfig));
      }
    
      private native static HybridData initHybrid(ReadableNativeArray jscConfig);
    }
    

    JSCJavaScriptExecutor的构造函数中调用initHybridn函数,这个函数在rn中反复的出现,它的主要作用是找到于java相对应的c++类并调用其构造方法生成对象,把new出来对象的地址放到java的HybridData对象中。其中与JSCJavaScriptExecutor对应的C++类是JSCJavaScriptExecutorHolder(后面再介绍)。接着往下看,发现函数最后会调用ReactContextInitAsyncTask的doInBackground方法:

    @Override
        protected Result<ReactApplicationContext> doInBackground(ReactContextInitParams... params) {
          ...
          try {
            //创建JavaScriptExecutor实例
            JavaScriptExecutor jsExecutor = params[0].getJsExecutorFactory().create();
            return Result.of(createReactContext(jsExecutor, params[0].getJsBundleLoader()));
          } catch (Exception e) {
            return Result.of(e);
          }
        }
    

    createReactContext函数比较长,此处选择比较重要的功能进行分析,剩下的可以自自行阅读,在分析代码之前,先看几个重要的类:
    JSBundleLoader:bundle.js文件加载器,在rn中有三种加载方式:1、加载本地文件;2、加载网络文件,并将文件缓存;3、加载网络文件,用于debug调试。
    ModuleSpec:NativeModule的包装类,主要是为了实现module的懒加载,由于rn中native module比较多,为了节省成本,rn中采用时懒加载的策略,只有相应的module使用时才进行创建。
    JavaScriptModule接口类,用于java调用js的接口,在rn中没有实现类,具体如何使用后面再介绍。
    JavaScriptModuleRegistry:JavaScriptModule的注册表。
    NativeModuleRegistry:NativeModule的注册表,用于管理NativeModule列表。
    NativeModule:java暴露给js调用的api接口,如果想创建自己的module,需要继承这个接口。
    ReactPackage:组件配置接口类,通过createNativeModules、createJSModules和createViewManagers等API去创建本地模块,JS模块及视图组件等。ReactPackage分为rn核心的CoreModulesPackage和业务方可选的基础MainReactPackage类,其中CoreModulesPackage封装了大部分通信功能。
    createReactContext函数:

      private ReactApplicationContext createReactContext(
          JavaScriptExecutor jsExecutor,
          JSBundleLoader jsBundleLoader) {
        ...
        //初始化ReactApplicationContext实例
        final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
       try {
          CoreModulesPackage coreModulesPackage =
            new CoreModulesPackage(
              this,
              mBackBtnHandler,
              mUIImplementationProvider,
              mLazyViewManagersEnabled);
          //将ReactPackage配置的modeles添加到nativeRegistryBuilder和jsModulesBuilder中
          processPackage(
            coreModulesPackage,
            reactContext,
            moduleSpecs,
            reactModuleInfoMap,
            jsModulesBuilder);
        } finally {
          ...
        }
        ...
        
        CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
         .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
            .setJSExecutor(jsExecutor)
            .setRegistry(nativeModuleRegistry)
            .setJSModuleRegistry(jsModulesBuilder.build())
            .setJSBundleLoader(jsBundleLoader)
            .setNativeModuleCallExceptionHandler(exceptionHandler);
    
        final CatalystInstance catalystInstance;
        try {
          catalystInstance = catalystInstanceBuilder.build();
        } finally {
          ...
        }
    
        reactContext.initializeWithInstance(catalystInstance);
        catalystInstance.runJSBundle();
    
        return reactContext;
      }
    

    这个函数主要有三个功能:
    1、根据ReactPackage生成js module和native module的注册表
    2、创建CatalystInstance实例
    3、加载bundle文件

    生成注册表代码比较简单,这里就不做介绍了,下面我们看CatalystInstanceImpl的构造函数:

      private CatalystInstanceImpl(
          final ReactQueueConfigurationSpec ReactQueueConfigurationSpec,
          final JavaScriptExecutor jsExecutor,
          final NativeModuleRegistry registry,
          final JavaScriptModuleRegistry jsModuleRegistry,
          final JSBundleLoader jsBundleLoader,
          NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
        ...
        //native函数,主要是为了将创建C++实例并将指针地址保存到java中
        
        mHybridData = initHybrid();
        
        mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
            ReactQueueConfigurationSpec,
            new NativeExceptionHandler());
        mBridgeIdleListeners = new CopyOnWriteArrayList<>();
        mJavaRegistry = registry;
        mJSModuleRegistry = jsModuleRegistry;
        mJSBundleLoader = jsBundleLoader;
        mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
        mTraceListener = new JSProfilerTraceListener(this);
    
        initializeBridge(
          new BridgeCallback(this),
          jsExecutor,
          mReactQueueConfiguration.getJSQueueThread(),
          mReactQueueConfiguration.getNativeModulesQueueThread(),
          mJavaRegistry.getModuleRegistryHolder(this));
        mMainExecutorToken = getMainExecutorToken();
      }
    

    构造函数有有两个重要的参数:
    1、ReactQueueConfigurationSpec:用于配置消息线程,在rn中有三个消息线程:UI线程、JS线程、Native线程,其中native调用js的代码会JS线程运行,JS调用native的代码会在Native线程中执行。

    2、ModuleRegistryHolder:Native Module的封装类,将java层Native Module信息传递给c++层。

    public class ModuleRegistryHolder {
      private final HybridData mHybridData;
      private static native HybridData initHybrid(
        CatalystInstanceImpl catalystInstanceImpl,
        Collection<JavaModuleWrapper> javaModules,
        Collection<CxxModuleWrapper> cxxModules);
    
      public ModuleRegistryHolder(CatalystInstanceImpl catalystInstanceImpl,
                                  Collection<JavaModuleWrapper> javaModules,
                                  Collection<CxxModuleWrapper> cxxModules) {
        mHybridData = initHybrid(catalystInstanceImpl, javaModules, cxxModules);
      }
    }
    

    上面已经说过initHybrid的工作,此处会在创建C++中ModuleRegistryHolder对象。接着调用initializeBridge函数来初始化,initializeBridge是native方法:

    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,
        ModuleRegistryHolder* mrh) {
    
      instance_->initializeBridge(folly::make_unique<JInstanceCallback>(callback),
                                  jseh->getExecutorFactory(),
                                  folly::make_unique<JMessageQueueThread>(jsQueue),
                                  folly::make_unique<JMessageQueueThread>(moduleQueue),
                                  mrh->getModuleRegistry());
    }
    
    

    JavaScriptExecutorHolder:对应于java层中的JavaScriptExecutor的C++对象,getExecutorFactory()返回JSCExecutorFactory对象,用于生成js解析器。
    ModuleRegistryHolder:java中native module的包装类,其构造函数:

    ModuleRegistryHolder.cpp
    ModuleRegistryHolder::ModuleRegistryHolder(
        CatalystInstanceImpl* catalystInstanceImpl,
        jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
        jni::alias_ref<jni::JCollection<CxxModuleWrapper::javaobject>::javaobject> cxxModules) {
      std::vector<std::unique_ptr<NativeModule>> modules;
      std::weak_ptr<Instance> winstance(catalystInstanceImpl->getInstance());
      for (const auto& jm : *javaModules) {
        modules.emplace_back(folly::make_unique<JavaNativeModule>(jm));
      }
      for (const auto& cm : *cxxModules) {
        modules.emplace_back(
          folly::make_unique<CxxNativeModule>(winstance, std::move(cthis(cm)->getModule())));
      }
    
      registry_ = std::make_shared<ModuleRegistry>(std::move(modules));
    }
    }
    

    将java层的对象分装成JavaNativeModule和CxxNativeModule对象,并将生成的对象注册到ModuleRegistry对象中,ModuleRegistry和上面提高的NativeModuleRegistry功能相似,是C++端module的注册表。继续往下走,会调用Instance的initializeBridge函数:

    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);
    
      jsQueue->runOnQueueSync(
        [this, &jsef, moduleRegistry, jsQueue,
         nativeQueue=folly::makeMoveWrapper(std::move(nativeQueue))] () mutable {
          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();
        });
    }
    

    MessageQueueThread对应于java层MessageQueueThread,进行线程转换变成js thread,在这个函数会调用NativeToJsBridge的构造函数,NativeToJsBridge:Native调用JS的桥梁。

    NativeToJsBridge.cpp
    
    NativeToJsBridge::NativeToJsBridge(
        JSExecutorFactory* jsExecutorFactory,
        std::shared_ptr<ModuleRegistry> registry,
        std::shared_ptr<MessageQueueThread> jsQueue,
        std::unique_ptr<MessageQueueThread> nativeQueue,
        std::shared_ptr<InstanceCallback> callback)
        : m_destroyed(std::make_shared<bool>(false))
        , m_mainExecutorToken(callback->createExecutorToken())
        , m_delegate(
          std::make_shared<JsToNativeBridge>(
            this, registry, std::move(nativeQueue), callback)) {
      std::unique_ptr<JSExecutor>
    
      mainExecutor =
        jsExecutorFactory->createJSExecutor(m_delegate, jsQueue);
      
      m_mainExecutor = mainExecutor.get();
      registerExecutor(m_mainExecutorToken, std::move(mainExecutor), jsQueue);
    }
    

    m_delegate是JsToNativeBridge,用于JS调用Native函数,和NativeToJsBridge一起作为连接java和js通信的桥梁。这个构造函数的主要是创建js的执行器,这里的mainExecutor对象对应于JSCExecutor对象,JSCExecutor构造函数中对js的执行环境进行初始化,并且向JavaScriptCore中注册了几个c++的方法供js端调用,这里就不做介绍了,有兴趣的可以自己阅读代码。到这里initializeBridge整个函数就全部介绍完毕了。
    下面回到ReactInstanceManager中的createReactContext函数中,接着调用CatalystInstanceImpl的runJSBundle方法,接着看runJSBundle函数,发现runJSBundle函数会调用JSBundleLoader的loadScript方法,前面我们介绍过JSBundleLoader有三种方式,我们假设使用的时文件加载的方式,跟着函数一步步走下去,最后会走到CatalystInstanceImpl的loadScriptFromFile函数,这个又是一个native方法,查看CatalystInstanceImpl.cpp的代码,最后进入NativeToJsBridge.cpp中loadApplication方法:

    NativeToJsBridge.cpp
    
    void NativeToJsBridge::loadApplication(
        std::unique_ptr<JSModulesUnbundle> unbundle,
        std::unique_ptr<const JSBigString> startupScript,
        std::string startupScriptSourceURL) {
        //进行线程转换,把函数抛到js thread的队列中
      runOnExecutorQueue(
          m_mainExecutorToken,
          [unbundleWrap=folly::makeMoveWrapper(std::move(unbundle)),
           startupScript=folly::makeMoveWrapper(std::move(startupScript)),
           startupScriptSourceURL=std::move(startupScriptSourceURL)]
            (JSExecutor* executor) mutable {
    
        auto unbundle = unbundleWrap.move();
        if (unbundle) {
          executor->setJSModulesUnbundle(std::move(unbundle));
        }
        executor->loadApplicationScript(std::move(*startupScript),
                                        std::move(startupScriptSourceURL));
      });
    }
    

    JSCExecutor.cpp中的loadApplicationScript函数:

    JSCExecutor.cpp
    
    void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script, std::string sourceURL) {
    //JavaScriptCore函数,执行js代码
    evaluateScript(m_context, jsScript, jsSourceURL);
    
      if (m_delegate) {
        bindBridge();
        flush();
      }
    }
    

    m_delegate为上面介绍的JsToNativeBridge对象,这里不为null,后面就会执行bindBridge函数:

    JSCExecutor.cpp
    void JSCExecutor::bindBridge() throw(JSException) {
      
      auto global = Object::getGlobalObject(m_context);
      auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
      if (batchedBridgeValue.isUndefined()) {
        throwJSExecutionException("Could not get BatchedBridge, make sure your bundle is packaged correctly");
      }
    
      auto batchedBridge = batchedBridgeValue.asObject();
      m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
      m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject();
      m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
      m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue").asObject();
    }
    

    这个函数主要实现下面几个功能:
    1、从js执行环境中取出全局变量__fbBatchedBridge放到global变量中。
    2、将global中某些特定的函数对象映射到C++对象中,这样我们就可以通过C++对象调用js的代码,假设我们想要调用js端__fbBatchedBridge的flushQueue方法,在C++中就可以使用m_flushedQueueJS->callAsFunction()就可以实现,那么__fbBatchedBridge在js端到底是个什么东西那?
    查看js代码,在BatchBridge.js中找到了__fbBatchedBridge的定义

    const MessageQueue = require('MessageQueue');
    const BatchedBridge = new MessageQueue();
    ...
    Object.defineProperty(global, '__fbBatchedBridge', {
      configurable: true,
      value: BatchedBridge,
    });
    

    从上面可以看出__fbBatchedBridge就是MessageQueue对象,后面再介绍MessageQueue。
    到这里整个rn的初始化和bundle加载就基本上介绍完毕了,下面介绍一下java和js之间如何通信的。

    二、java和js之间通信的过程

    2.1 java调用js过程

    举一个列子:假设我们想要执行js端AppRegistry.runApplication()函数,我们应该怎么办那?

    首先要拿到ReactContext实例,然后调用getJSModule方法拿到AppRegistry实例,最后调用runApplication方法就可以了,很简单吧,那么看代码里面如何实现的?
    ReactContext.getJSModule函数:

    public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
        ...
        return mCatalystInstance.getJSModule(jsInterface);
      }
    

    ReactContext中的getJSModule很简单,直接调用CatalystInstanceImpl的JavaScriptModule方法:

     @Override
      public <T extends JavaScriptModule> T getJSModule(ExecutorToken executorToken, Class<T> jsInterface) {
        return Assertions.assertNotNull(mJSModuleRegistry)
            .getJavaScriptModule(this, executorToken, jsInterface);
      }
    

    调用JavaScriptModuleRegistry的getJavaScriptModule方法,
    JavaScriptModuleRegistry前面提过,是管理js module的注册表,接着看一下内部实现:

    JavaScriptModuleRegistry.java
    
      public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
        CatalystInstance instance,
        ExecutorToken executorToken,
        Class<T> moduleInterface) {
        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;
        }
    
        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;
      }
    
    

    这个函数的流程比较简单:首先判断js module是否已经生成了,如果已经生成了就直接返回内存中的对象,假设我们是第一次调用,那么就会执行后面的方法,使用java的动态代理来生成js module的实例,关于动态代理,我们知道实际的处理逻辑都在InvocationHandler中invoke方法中执行,直接看InvocationHandler的实现类JavaScriptModuleInvocationHandler中的invoke函数:

    @Override
        public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
          ExecutorToken executorToken = mExecutorToken.get();
          ...
          NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
          mCatalystInstance.callFunction(
            executorToken,
            mModuleRegistration.getName(),
            method.getName(),
            jsArgs
          );
          return null;
        }
    

    invoke方法比较简单,直接调用mCatalystInstance的callFunction(...)方法,看着这里就比较明白了,调用AppRegistery的runApplictaion(args)方法实际上是调用CatalystInstance的callFuction(,"AppRegistry","runApplictaion",args)方法。其中NativeArray类,用于rn中java端和C++端进行数据传递的数据结构,主要目的是节省内存,便于管理,有兴趣的可以自行阅读源码。
    这时大概java层流程就大概清楚了,我们看C++层,一步步往下走,最后会到NativeToJsBridge中的callFunction函数:

    NativeToJsBridge.cpp
    void NativeToJsBridge::callFunction(
        ExecutorToken executorToken,
        std::string&& module,
        std::string&& method,
        folly::dynamic&& arguments) {
    
      runOnExecutorQueue(executorToken, [module = std::move(module), method = std::move(method), arguments = std::move(arguments), tracingName = std::move(tracingName), systraceCookie] (JSExecutor* executor) {
        executor->callFunction(module, method, arguments);
      });
    }
    

    runOnExecutorQueue的函数讲过,不清楚请往前看,后面会执行JSExecutor的callFunction函数,其中module是想要调用js端对象的名称,method是js对象中的方法名称,arguments是方法参数。JSCExecutor::callFunction函数:

    JSCExecutor.cpp
    
    void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {
     
      auto result = [&] {
        try {
          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 (...) {
          
        }
      }();
    
      callNativeModules(std::move(result));
    }
    

    m_callFunctionReturnFlushedQueueJS是js全局对象_fbBatchedBridge中的callFunctionReturnFlushedQueue对象,对它调用callAsFunction方法来,相当于执行_fbBatchedBridge.callFunctionReturnFlushedQueue函数。callNativeModules函数主要的功能是将js的执行结果返回给native函数,这里需要注意的是这个过程不是线性的,前面说过_fbBatchedBridge是MessageQueue对象,查看MessageQueue.js中的callFunctionReturnFlushedQueue函数:

    MessageQueue.js
    MessageQueue
    callFunctionReturnFlushedQueue(module: string, method: string, args: Array<any>) {
    //es6的新特性箭头函数
        guard(() => {
          this.__callFunction(module, method, args);
          this.__callImmediates();
        });
        return this.flushedQueue();
      }
    

    MessageQueued的__callFunction函数:

    __callFunction(module: string, method: string, args: Array<any>) {
        ...
        const moduleMethods = this._callableModules[module];
        ...
        const result = moduleMethods[method].apply(moduleMethods, args);
        ...
        return result;
      }
    

    MessageQueue内部有一个js模块的配置数组,每个js模块会在js加载时将自己注册到MessageQueue配置表_callableModules中,它以moduleId为key,module对象为value进行存储,此时这个函数的功能就是调用js中module模块中method方法。
    到这里还有个问题:这个配置表是如何生成的?这里还是以AppRegistry为例,查看AppRegistry.js的代码:

    BatchedBridge.registerCallableModule(
      'AppRegistry',
      AppRegistry
    );
    

    在加载AppRegistry.js时会调用BatchedBridge.registerCallableModule方法,前面我们讲过BatchedBridge对象就是MessageQueue对象,会调用MessageQueue.registerCallableModule函数:

    registerCallableModule(name: string, module: Object) {
        this._callableModules[name] = module;
      }
    

    js端配置表如何生成到这里也就结束了,总结来说,就是js文件加载时每个模块会将通过key和value的形式注册到MessageQueue中,工java端调用。在java调用接口时需要注意的时模块名称必须和js注册的名称完全一样,否则就会找不到这个module,执行不成功。到这里整个java调用js的过程就就结束了。接着介绍js到native的调用过程。

    2.2 js调用native过程

    还是一个例子来介绍这一过程,在Android中有个常用的控件Toast,那么js中如何调用native的Toast那?在rn中对这个过程进行了封装,我们想显示hello world,在js中只需要调用ToastAndroid.show('hello world', ToastAndroid.SHORT);就可以了,那么它是如何实现的那?查看ToastAndroid.js的代码:

    ar RCTToastAndroid = require('NativeModules').ToastAndroid;
    var ToastAndroid = {
      SHORT: RCTToastAndroid.SHORT,
      LONG: RCTToastAndroid.LONG,
      TOP: RCTToastAndroid.TOP,
      BOTTOM: RCTToastAndroid.BOTTOM,
      CENTER: RCTToastAndroid.CENTER,
    
      show: function (
        message: string,
        duration: number
      ): void {
        RCTToastAndroid.show(message, duration);
      },
    
      showWithGravity: function (
        message: string,
        duration: number,
        gravity: number,
      ): void {
        RCTToastAndroid.showWithGravity(message, duration, gravity);
      },
    };
    
    module.exports = ToastAndroid;
    

    调用ToastAndroid的show函数就会RCTToastAndroid中的show函数,RCTToastAndroid是NativeModules.js中NativeModules对象,查看NativeModules.js的代码NativeModules是一个空的hashmap对象,key为moduleName的名称,value为module的对象,下面看一下NativeModules是如何生成的:

    NativeModules.js
    if (global.nativeModuleProxy) {
      NativeModules = global.nativeModuleProxy;
    } else {
      const bridgeConfig = global.__fbBatchedBridgeConfig;
    
      (bridgeConfig.remoteModuleConfig || []).forEach((config: ModuleConfig, moduleID: number) => {
        const info = genModule(config, moduleID);
        if (!info) {
          return;
        }
    
        if (info.module) {
          NativeModules[info.name] = info.module;
        } else {
          defineLazyObjectProperty(NativeModules, info.name, {
            get: () => loadModule(info.name, moduleID)
          });
        }
      });
    }
    

    上面解析过BatchBridge.js,里面对全局的global对象进行赋值为MessageQueue,查看MessageQueue是否nativeModuleProxy对象,发现整个js中没有找到nativeModuleProxy,但是有一点我们需要注意的是我们在JSCExecutor注册了很多C++的函数供js端调用,global中函数对象包含JSCExecutor注册的C++中的函数,在JSCExecutor.cpp中nativeModuleProxy对应这个C++端的getNativeModule函数,查看getNativeModule函数:

    JSCExecutor.cpp
    JSValueRef JSCExecutor::getNativeModule(JSObjectRef object, JSStringRef propertyName) {
      ...
      return m_nativeModules.getModule(m_context, propertyName);
    }
    

    m_nativeModules是SCJNativeModules类对象,getModule函数:

    SCJNativeModules
    JSValueRef JSCNativeModules::getModule(JSContextRef context, JSStringRef jsName) {
      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);
      }
    
    //如果缓存中没有则生成
      auto module = createModule(moduleName, context);
      if (!module.hasValue()) {
        return Value::makeUndefined(context);
      }
    
     ...
      return static_cast<JSObjectRef>(result->second);
    }
    

    createModule函数:

    JSCNativeModules.cpp
    folly::Optional<Object> JSCNativeModules::createModule(const std::string& name, JSContextRef context) {
    //没有产生过native配置表
      if (!m_genNativeModuleJS) {
        auto global = Object::getGlobalObject(context);
        获取js全局对象中__fbGenNativeModule属性
        m_genNativeModuleJS = global.getProperty("__fbGenNativeModule").asObject();
        m_genNativeModuleJS->makeProtected();
        //通过C++中NativeModule包装类调用java端的代码,生成native module实例,前面已经说过,native module是采用懒惰加载的方式加载的,在这块可以体会到
        m_moduleRegistry->moduleNames();
      }
    
     //生成配置表,这个配置表中有三类信息:常量,函数和函数类型
      auto result = m_moduleRegistry->getConfig(name);
      if (!result.hasValue()) {
        return nullptr;
      }
    
     //调用js中的__fbGenNativeModule函数将生成的配置表中的函数信息传递到js中
      Value moduleInfo = m_genNativeModuleJS->callAsFunction({
        Value::fromDynamic(context, result->config),
        Value::makeNumber(context, result->index)
      });
      return moduleInfo.asObject().getProperty("module").asObject();
    }
    

    生成配置表的函数比较简单,这里不做分析,感兴趣的同学可以自行阅读代码,生成配置结构大致如下:
    生成的配置表的格式大概是:

    { 'module名称', ,{ '常量key':'常量value'} { 'show', 'showWithGravity' },
    }
    后面会回调给global对象的__fbGenNativeModule方法,生成NativeModules列表,这里就不做介绍,解感兴趣的可以自行阅读源码,RCTToastAndroid.show(message, duration);最后实际上会变成MessageQueue.enqueueNativeCall(1,"show",{"hello world",0},null,null)函数;
    MessageQueue.js中的enqueueNativeCall函数:

    MessageQueue.js
    enqueueNativeCall(moduleID: number, methodID: number, params: Array < any > , onFail: ? Function, onSucc : ? Function) {
      ...
      //判断是否可以调用native的方法,当两个相继调用的函数超过MIN_TIME_BETWEEN_FLUSHES_MSs才会调用nativeFlushQueueImmediate方法
      const now = new Date().getTime();
      if (global.nativeFlushQueueImmediate &&
        now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS) {
        global.nativeFlushQueueImmediate(this._queue);
        this._queue = [
          [],
          [],
          [], this._callID
        ];
        this._lastFlush = now;
      }
      ...
    }
    

    nativeFlushQueueImmediate是C++注册的本地函数,对应于JSCExecutor::nativeFlushQueueImmediate函数,一步步往下走下去最后会执行java端JavaModuleWrapper类中的invoke方法:

    JavaModuleWrapper.java
    @DoNotStrip
      public void invoke(ExecutorToken token, int methodId, ReadableNativeArray parameters) {
        
        mMethods.get(methodId).invoke(mCatalystInstance, token, parameters);
      }
    

    mMethods:native module中包含的的函数;
    methodId:js端要执行的函数名称;
    parameters:js端传递过来的参数;
    这个方法最后会调用ToastModule的show方法,整个js调用native流程到这里就介绍完毕了。

    相关文章

      网友评论

        本文标题:ReactNative Android源码分析

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