ReactNative Android源码分析

这篇文章针对于对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 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 javaModules,
    Collection cxxModules);

  public ModuleRegistryHolder(CatalystInstanceImpl catalystInstanceImpl,
                              Collection javaModules,
                              Collection cxxModules) {
    mHybridData = initHybrid(catalystInstanceImpl, javaModules, cxxModules);
  }
}

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

CatalystInstanceImpl.cpp

void CatalystInstanceImpl::initializeBridge(
    jni::alias_ref callback,
    // This executor is actually a factory holder.
    JavaScriptExecutorHolder* jseh,
    jni::alias_ref jsQueue,
    jni::alias_ref moduleQueue,
    ModuleRegistryHolder* mrh) {

  instance_->initializeBridge(folly::make_unique(callback),
                              jseh->getExecutorFactory(),
                              folly::make_unique(jsQueue),
                              folly::make_unique(moduleQueue),
                              mrh->getModuleRegistry());
}

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

ModuleRegistryHolder.cpp
ModuleRegistryHolder::ModuleRegistryHolder(
    CatalystInstanceImpl* catalystInstanceImpl,
    jni::alias_ref::javaobject> javaModules,
    jni::alias_ref::javaobject> cxxModules) {
  std::vector> modules;
  std::weak_ptr winstance(catalystInstanceImpl->getInstance());
  for (const auto& jm : *javaModules) {
    modules.emplace_back(folly::make_unique(jm));
  }
  for (const auto& cm : *cxxModules) {
    modules.emplace_back(
      folly::make_unique(winstance, std::move(cthis(cm)->getModule())));
  }

  registry_ = std::make_shared(std::move(modules));
}
}

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

Instance.cpp
void Instance::initializeBridge(
    std::unique_ptr callback,
    std::shared_ptr jsef,
    std::shared_ptr jsQueue,
    std::unique_ptr nativeQueue,
    std::shared_ptr moduleRegistry) {
  callback_ = std::move(callback);

  jsQueue->runOnQueueSync(
    [this, &jsef, moduleRegistry, jsQueue,
     nativeQueue=folly::makeMoveWrapper(std::move(nativeQueue))] () mutable {
      nativeToJsBridge_ = folly::make_unique(
          jsef.get(), moduleRegistry, jsQueue, nativeQueue.move(), callback_);

      std::lock_guard 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 registry,
    std::shared_ptr jsQueue,
    std::unique_ptr nativeQueue,
    std::shared_ptr callback)
    : m_destroyed(std::make_shared(false))
    , m_mainExecutorToken(callback->createExecutorToken())
    , m_delegate(
      std::make_shared(
        this, registry, std::move(nativeQueue), callback)) {
  std::unique_ptr

  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 unbundle,
    std::unique_ptr 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 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 getJSModule(Class jsInterface) {
    ...
    return mCatalystInstance.getJSModule(jsInterface);
  }

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

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

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

JavaScriptModuleRegistry.java

  public synchronized  T getJavaScriptModule(
    CatalystInstance instance,
    ExecutorToken executorToken,
    Class moduleInterface) {
    HashMap, 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) {
//es6的新特性箭头函数
    guard(() => {
      this.__callFunction(module, method, args);
      this.__callImmediates();
    });
    return this.flushedQueue();
  }

MessageQueued的__callFunction函数:

__callFunction(module: string, method: string, args: Array) {
    ...
    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(it->second);
  }

//如果缓存中没有则生成
  auto module = createModule(moduleName, context);
  if (!module.hasValue()) {
    return Value::makeUndefined(context);
  }

 ...
  return static_cast(result->second);
}

createModule函数:

JSCNativeModules.cpp
folly::Optional 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源码分析)