美文网首页
ReactNative Android 运行原理之

ReactNative Android 运行原理之

作者: 耗子_wo | 来源:发表于2021-02-06 23:03 被阅读0次

    这一期我们来介绍下ReactNative Android 运行原理之<JAVA TO JavaScript>,由于整个流程步骤非常多,比较的复杂,但是有些朋友又想简单的去理解这个调用原理(至少我一开始也希望是这样的,但是发现非常困难),所以这一期我们来个轻松愉快的解说,我们通过这篇文章帮助大家通俗简单的去理解这个调用流程,让我们开始吧:

    Java要能调用到JS需要在Java层注册JS模块,先来看下JS模块的注册过程。
    系统注册了一些常用的JS模块,在CoreModulesPackage的createJSModules中注册了一些系统核心的JS模块,比如AppRegistry(RN组件注册模块)/RCTEventEmitter(事件发射模块)等。

    class CoreModulesPackage implements ReactPackage{
      @Override
      public List<NativeModule> createNativeModules(
          ReactApplicationContext catalystApplicationContext) {
        ......
        return Arrays.<NativeModule>asList(
            new AnimationsDebugModule(
                catalystApplicationContext,
                mReactInstanceManager.getDevSupportManager().getDevSettings()),
            new AndroidInfoModule(),
            new DeviceEventManagerModule(catalystApplicationContext, mHardwareBackBtnHandler),
            new ExceptionsManagerModule(mReactInstanceManager.getDevSupportManager()),
            new Timing(catalystApplicationContext),
            new SourceCodeModule(
                mReactInstanceManager.getSourceUrl(),
                mReactInstanceManager.getDevSupportManager().getSourceMapUrl()),
            uiManagerModule,
            new DebugComponentOwnershipModule(catalystApplicationContext));
      }
      
      @Override
      public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Arrays.asList(
            DeviceEventManagerModule.RCTDeviceEventEmitter.class,
            JSTimersExecution.class,
            RCTEventEmitter.class,
            RCTNativeAppEventEmitter.class,
            AppRegistry.class,
            com.facebook.react.bridge.Systrace.class,
            DebugComponentOwnershipModule.RCTDebugComponentOwnership.class);
      }
    }
    
    public interface ReactPackage {
    
      /**
       * @param reactContext react application context that can be used to create modules
       * @return list of native modules to register with the newly created catalyst instance
       */
      List<NativeModule> createNativeModules(ReactApplicationContext reactContext);
    
      /**
       * @return list of JS modules to register with the newly created catalyst instance.
       *
       * IMPORTANT: Note that only modules that needs to be accessible from the native code should be
       * listed here. Also listing a native module here doesn't imply that the JS implementation of it
       * will be automatically included in the JS bundle.
       */
      List<Class<? extends JavaScriptModule>> createJSModules();
    
      /**
       * @return a list of view managers that should be registered with {@link UIManagerModule}
       */
      List<ViewManager> createViewManagers(ReactApplicationContext reactContext);
    }
    

    以RCTEventEmitter这个JavaScriptModule模块为例来看下JS模块在Java层的实现。

    public interface RCTEventEmitter extends JavaScriptModule {
      public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event);
      public void receiveTouches(
          String eventName,
          WritableArray touches,
          WritableArray changedIndices);
    }
    

    我们先来看看JavaScriptModulesConfig,他主要是对每个JavaScriptModule构造JavaScriptModuleRegistration,存放在mModules中

    /**
     * Class stores configuration of javascript modules that can be used across the bridge
     */
    public class JavaScriptModulesConfig {
    
      private final List<JavaScriptModuleRegistration> mModules;
    
      private JavaScriptModulesConfig(List<JavaScriptModuleRegistration> modules) {
        mModules = modules;
      }
    
      /*package*/ List<JavaScriptModuleRegistration> getModuleDefinitions() {
        return mModules;
      }
    
      /*package*/ void writeModuleDescriptions(JsonGenerator jg) throws IOException {
        jg.writeStartObject();
        for (JavaScriptModuleRegistration registration : mModules) {
          jg.writeObjectFieldStart(registration.getName());
          appendJSModuleToJSONObject(jg, registration);
          jg.writeEndObject();
        }
        jg.writeEndObject();
      }
    
      private void appendJSModuleToJSONObject(
          JsonGenerator jg,
          JavaScriptModuleRegistration registration) throws IOException {
        jg.writeObjectField("moduleID", registration.getModuleId());
        jg.writeObjectFieldStart("methods");
        for (Method method : registration.getMethods()) {
          jg.writeObjectFieldStart(method.getName());
          jg.writeObjectField("methodID", registration.getMethodId(method));
          jg.writeEndObject();
        }
        jg.writeEndObject();
      }
    
      public static class Builder {
    
        private int mLastJSModuleId = 0;
        private List<JavaScriptModuleRegistration> mModules =
            new ArrayList<JavaScriptModuleRegistration>();
    
        public Builder add(Class<? extends JavaScriptModule> moduleInterfaceClass) {
          int moduleId = mLastJSModuleId++;
          mModules.add(new JavaScriptModuleRegistration(moduleId, moduleInterfaceClass));
          return this;
        }
    
        public JavaScriptModulesConfig build() {
          return new JavaScriptModulesConfig(mModules);
        }
      }
    }
    
    /**
     * Registration info for a {@link JavaScriptModule}. 
        Maps its methods to method ids.
     */
    class JavaScriptModuleRegistration {
    
      private final int mModuleId;
      private final Class<? extends JavaScriptModule> mModuleInterface;
      private final Map<Method, Integer> mMethodsToIds;
      private final Map<Method, String> mMethodsToTracingNames;
    
      JavaScriptModuleRegistration(int moduleId, Class<? extends JavaScriptModule> moduleInterface) {
        mModuleId = moduleId;
        mModuleInterface = moduleInterface;
    
        mMethodsToIds = MapBuilder.newHashMap();
        mMethodsToTracingNames = MapBuilder.newHashMap();
        final Method[] declaredMethods = mModuleInterface.getDeclaredMethods();
        Arrays.sort(declaredMethods, new Comparator<Method>() {
          @Override
          public int compare(Method lhs, Method rhs) {
            return lhs.getName().compareTo(rhs.getName());
          }
        });
    
        // Methods are sorted by name so we can dupe check and have obvious ordering
        String previousName = null;
        for (int i = 0; i < declaredMethods.length; i++) {
          Method method = declaredMethods[i];
          String name = method.getName();
          Assertions.assertCondition(
              !name.equals(previousName),
              "Method overloading is unsupported: " + mModuleInterface.getName() + "#" + name);
          previousName = name;
    
          mMethodsToIds.put(method, i);
          mMethodsToTracingNames.put(method, "JSCall__" + getName() + "_" + method.getName());
        }
      }
      ......
    }
    

    到这里就有了所有的JavaScriptModules,并且都扫描存放在JavaScriptModulesConfig中,那么RN框架是怎么使用的?我们再来看看ReactInstanceManagerImpl,他将JavaScriptModulesConfig用来实例化catalystInstance,这个是三方通信的中转站。

     //createCatalystInstance---Java/JS/C++三方通信总管
        CatalystInstanceImpl.Builder catalystInstanceBuilder = new  CatalystInstanceImpl.Builder()
            .setCatalystQueueConfigurationSpec(CatalystQueueConfigurationSpec.createDefault())
            .setJSExecutor(jsExecutor)
            .setRegistry(nativeModuleRegistry)
            .setJSModulesConfig(javaScriptModulesConfig)
            .setJSBundleLoader(jsBundleLoader)
            .setNativeModuleCallExceptionHandler(exceptionHandler);
    
    Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
        CatalystInstance catalystInstance;
        try {
          catalystInstance = catalystInstanceBuilder.build();
        } finally {
          Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
        }
    

    再接着看看实现类CatalystInstanceImpl:

    private CatalystInstanceImpl(
          final CatalystQueueConfigurationSpec catalystQueueConfigurationSpec,
          final JavaScriptExecutor jsExecutor,
          final NativeModuleRegistry registry,
          final JavaScriptModulesConfig jsModulesConfig,
          final JSBundleLoader jsBundleLoader,
          NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
        ...
        mJSModuleRegistry = new JavaScriptModuleRegistry(CatalystInstanceImpl.this, jsModulesConfig);
        ...
      }
    

    再接下来需要到JavaScriptModuleRegistry中看看:

    
    /*package*/ class JavaScriptModuleRegistry {
    
      private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;
    
      public JavaScriptModuleRegistry(
          CatalystInstanceImpl instance,
          JavaScriptModulesConfig config) {
        mModuleInstances = new HashMap<>();
        for (JavaScriptModuleRegistration registration : config.getModuleDefinitions()) {
          Class<? extends JavaScriptModule> moduleInterface = registration.getModuleInterface();
          JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
              moduleInterface.getClassLoader(),
              new Class[]{moduleInterface},
              new JavaScriptModuleInvocationHandler(instance, registration));
    
          mModuleInstances.put(moduleInterface, interfaceProxy);
        }
      }
    
      public <T extends JavaScriptModule> T getJavaScriptModule(Class<T> moduleInterface) {
        return (T) Assertions.assertNotNull(
            mModuleInstances.get(moduleInterface),
            "JS module " + moduleInterface.getSimpleName() + " hasn't been registered!");
      }
    
      private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
    
        private final CatalystInstanceImpl mCatalystInstance;
        private final JavaScriptModuleRegistration mModuleRegistration;
    
        public JavaScriptModuleInvocationHandler(
            CatalystInstanceImpl catalystInstance,
            JavaScriptModuleRegistration moduleRegistration) {
          mCatalystInstance = catalystInstance;
          mModuleRegistration = moduleRegistration;
        }
    
        @Override
        public @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          String tracingName = mModuleRegistration.getTracingName(method);
          mCatalystInstance.callFunction(
              mModuleRegistration.getModuleId(),
              mModuleRegistration.getMethodId(method),
              Arguments.fromJavaArgs(args),
              tracingName);
          return null;
        }
      }
    }
    

    很明显这里就是对每个接口通过动态代理实例化一个代理对象,调用JavaScriptModule里面的方法(Java调用JavaScript方法)其实就是统一分发到JavaScriptModuleInvocationHandler中的invoke进行处理,在invoke方法中调用CatalystInstance.callFunction,CatalystInstance是一个接口,实现类CatalystInstanceImpl,看到CatalystInstanceImpl中的callFunction:

    /* package */ void callFunction(
          final int moduleId,
          final int methodId,
          final NativeArray arguments,
          final String tracingName) {
        if (mDestroyed) {
          FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");
          return;
        }
    
        incrementPendingJSCalls();
    
        final int traceID = mTraceID++;
        Systrace.startAsyncFlow(
            Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
            tracingName,
            traceID);
    
        mCatalystQueueConfiguration.getJSQueueThread().runOnQueue(
            new Runnable() {
              @Override
              public void run() {
                mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
    
                Systrace.endAsyncFlow(
                    Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
                    tracingName,
                    traceID);
    
                if (mDestroyed) {
                  return;
                }
    
                Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, tracingName);
                try {
                  Assertions.assertNotNull(mBridge).callFunction(moduleId, methodId, arguments);
                } finally {
                  Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
                }
              }
            });
      }
    

    通过这句话:Assertions.assertNotNull(mBridge).callFunction(moduleId, methodId, arguments); 就知道所有Java TO Javascript层的通信请求都是走的ReactBridge.callFunction,其实就是在JSQueueThread线程中调用ReactBridge的callFunction,是Native函数,到这里就从Java转到C++层了

    /**
     * Interface to the JS execution environment and means of transport for messages Java<->JS.
     */
    @DoNotStrip
    public class ReactBridge extends Countable {
    
      /* package */ static final String REACT_NATIVE_LIB = "reactnativejni";
    
      static {
        SoLoader.loadLibrary(REACT_NATIVE_LIB);
      }
    
      private final ReactCallback mCallback;
      private final JavaScriptExecutor mJSExecutor;
      private final MessageQueueThread mNativeModulesQueueThread;
    
      /**
       * @param jsExecutor the JS executor to use to run JS
       * @param callback the callback class used to invoke native modules
       * @param nativeModulesQueueThread the MessageQueueThread the callbacks should be invoked on
       */
      public ReactBridge(
          JavaScriptExecutor jsExecutor,
          ReactCallback callback,
          MessageQueueThread nativeModulesQueueThread) {
        mJSExecutor = jsExecutor;
        mCallback = callback;
        mNativeModulesQueueThread = nativeModulesQueueThread;
        initialize(jsExecutor, callback, mNativeModulesQueueThread);
      }
    
      @Override
      public void dispose() {
        mJSExecutor.close();
        mJSExecutor.dispose();
        super.dispose();
      }
    
      public void handleMemoryPressure(MemoryPressure level) {
        switch (level) {
          case MODERATE:
            handleMemoryPressureModerate();
            break;
          case CRITICAL:
            handleMemoryPressureCritical();
            break;
          default:
            throw new IllegalArgumentException("Unknown level: " + level);
        }
      }
    
      private native void initialize(
          JavaScriptExecutor jsExecutor,
          ReactCallback callback,
          MessageQueueThread nativeModulesQueueThread);
    
      /**
       * All native functions are not thread safe and appropriate queues should be used
       */
      public native void loadScriptFromAssets(AssetManager assetManager, String assetName);
      public native void loadScriptFromFile(@Nullable String fileName, @Nullable String sourceURL);
      public native void callFunction(int moduleId, int methodId, NativeArray arguments);
      public native void invokeCallback(int callbackID, NativeArray arguments);
      public native void setGlobalVariable(String propertyName, String jsonEncodedArgument);
      public native boolean supportsProfiling();
      public native void startProfiler(String title);
      public native void stopProfiler(String title, String filename);
      private native void handleMemoryPressureModerate();
      private native void handleMemoryPressureCritical();
    }
    

    我们先不急着往下去跟踪,因为在调用之前初始化的时候会涉及到一些重要参数传递的过程,我们先来看看再回头看看ReactBridge在CatalystInstanceImpl里面的初始化,初始化会ReactBridge调用setGlobalVariable,这是个Native函数,是在C++层注册用的,我们先分析下这个函数buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig)做了什么。

    private CatalystInstanceImpl(
          final CatalystQueueConfigurationSpec catalystQueueConfigurationSpec,
          final JavaScriptExecutor jsExecutor,
          final NativeModuleRegistry registry,
          final JavaScriptModulesConfig jsModulesConfig,
          final JSBundleLoader jsBundleLoader,
          NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
        ......
        try {
          mBridge = mCatalystQueueConfiguration.getJSQueueThread().callOnQueue(
              new Callable<ReactBridge>() {
                @Override
                public ReactBridge call() throws Exception {
                  Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "initializeBridge");
                  try {
                    return initializeBridge(jsExecutor, jsModulesConfig);
                  } finally {
                    Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
                  }
                }
              }).get(BRIDGE_SETUP_TIMEOUT_MS, TimeUnit.MILLISECONDS);
        } catch (Exception t) {
          throw new RuntimeException("Failed to initialize bridge", t);
        }
      }
    
      private ReactBridge initializeBridge(
          JavaScriptExecutor jsExecutor,
          JavaScriptModulesConfig jsModulesConfig) {
        mCatalystQueueConfiguration.getJSQueueThread().assertIsOnThread();
        Assertions.assertCondition(mBridge == null, "initializeBridge should be called once");
    
        Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactBridgeCtor");
        ReactBridge bridge;
        try {
          bridge = new ReactBridge(
              jsExecutor,
              new NativeModulesReactCallback(),
              mCatalystQueueConfiguration.getNativeModulesQueueThread());
        } finally {
          Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
        }
    
        Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "setBatchedBridgeConfig");
        try {
          bridge.setGlobalVariable(
              "__fbBatchedBridgeConfig",
              buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));
          bridge.setGlobalVariable(
              "__RCTProfileIsProfiling",
              Systrace.isTracing(Systrace.TRACE_TAG_REACT_APPS) ? "true" : "false");
        } finally {
          Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
        }
    
        return bridge;
      }
    

    在CatalystInstanceImpl中的实现,其实就是写一个JSON字符串,有两个字段"remoteModuleConfig"和"localModulesConfig",分别对应NativeModule(Native提供给JS调用)和JSModule(JS提供给Native调用)

    private String buildModulesConfigJSONProperty(
          NativeModuleRegistry nativeModuleRegistry,
          JavaScriptModulesConfig jsModulesConfig) {
        JsonFactory jsonFactory = new JsonFactory();
        StringWriter writer = new StringWriter();
        try {
          JsonGenerator jg = jsonFactory.createGenerator(writer);
          jg.writeStartObject();
          jg.writeFieldName("remoteModuleConfig");
          nativeModuleRegistry.writeModuleDescriptions(jg);
          jg.writeFieldName("localModulesConfig");
          jsModulesConfig.writeModuleDescriptions(jg);
          jg.writeEndObject();
          jg.close();
        } catch (IOException ioe) {
          throw new RuntimeException("Unable to serialize JavaScript module declaration", ioe);
        }
        return writer.getBuffer().toString();
      }
    

    再看看localModulesConfig都写入了什么,其实就是往JSON字符创中先写入接口名、moduleID、methods(方法名、methodID)等。

    /*package*/ void writeModuleDescriptions(JsonGenerator jg) throws IOException {
        jg.writeStartObject();
        for (JavaScriptModuleRegistration registration : mModules) {
          jg.writeObjectFieldStart(registration.getName());
          appendJSModuleToJSONObject(jg, registration);
          jg.writeEndObject();
        }
        jg.writeEndObject();
      }
    
      private void appendJSModuleToJSONObject(
          JsonGenerator jg,
          JavaScriptModuleRegistration registration) throws IOException {
        jg.writeObjectField("moduleID", registration.getModuleId());
        jg.writeObjectFieldStart("methods");
        for (Method method : registration.getMethods()) {
          jg.writeObjectFieldStart(method.getName());
          jg.writeObjectField("methodID", registration.getMethodId(method));
          jg.writeEndObject();
        }
        jg.writeEndObject();
      }
    

    我们已经想到了buildModulesConfigJSONProperty把所有的JavaScriptModule模块以moduleID+methodID形式生成JSON字符串,通过setGlobalVariable把JSON字符串预先存入了ReactBridge中,如下:

     bridge.setGlobalVariable(
              "__fbBatchedBridgeConfig",
              buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));
    

    我们再来看看JNI的注册部分,JNI入口react/jni/OnLoad.cpp,通过RegisterNatives方式注册的,JNI_OnLoad里面注册了setGlobalVariable和callFunction等native本地方法

    //jni/react/jni/OnLoad.cpp
    namespace bridge {
      ......
    
    static void setGlobalVariable(JNIEnv* env, jobject obj, jstring propName, jstring jsonValue) {
      auto bridge = extractRefPtr<Bridge>(env, obj);
      bridge->setGlobalVariable(fromJString(env, propName), fromJString(env, jsonValue));
    }
      ...
    } // namespace bridge
    
    extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
      return initialize(vm, [] {
        // get the current env
        JNIEnv* env = Environment::current();
        registerNatives("com/facebook/react/bridge/ReadableNativeMap$ReadableNativeMapKeySetIterator", {
        ......
        registerNatives("com/facebook/react/bridge/ReactBridge", {
            makeNativeMethod("initialize", "(Lcom/facebook/react/bridge/JavaScriptExecutor;Lcom/facebook/react/bridge/ReactCallback;Lcom/facebook/react/bridge/queue/MessageQueueThread;)V", bridge::create),
            makeNativeMethod(
              "loadScriptFromAssets", "(Landroid/content/res/AssetManager;Ljava/lang/String;)V",
              bridge::loadScriptFromAssets),
            makeNativeMethod("loadScriptFromFile", bridge::loadScriptFromFile),
            makeNativeMethod("callFunction", bridge::callFunction),
            makeNativeMethod("invokeCallback", bridge::invokeCallback),
            makeNativeMethod("setGlobalVariable", bridge::setGlobalVariable),
            makeNativeMethod("supportsProfiling", bridge::supportsProfiling),
            makeNativeMethod("startProfiler", bridge::startProfiler),
            makeNativeMethod("stopProfiler", bridge::stopProfiler),
            makeNativeMethod("handleMemoryPressureModerate", bridge::handleMemoryPressureModerate),
            makeNativeMethod("handleMemoryPressureCritical", bridge::handleMemoryPressureCritical),
    
        });
    }
    

    跟踪setGlobalVariable函数调用:

    void Bridge::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
      m_threadState->setGlobalVariable(propName, jsonValue);
    }
    

    继续跟踪:

    //jni/react/Bridge.cpp
    class JSThreadState {
    public:
      JSThreadState(const RefPtr<JSExecutorFactory>& jsExecutorFactory, Bridge::Callback&& callback) :
        m_callback(callback)
      {
        m_jsExecutor = jsExecutorFactory->createJSExecutor([this, callback] (std::string queueJSON, bool isEndOfBatch) {
          m_callback(parseMethodCalls(queueJSON), false /* = isEndOfBatch */);
        });
      }
    
      void setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
        m_jsExecutor->setGlobalVariable(propName, jsonValue);
      }
    
    private:
      std::unique_ptr<JSExecutor> m_jsExecutor;
      Bridge::Callback m_callback;
    };
    

    最终调用JSExecutor类的setGlobalVariable:

    //jni/react/JSCExecutor.cpp
    void JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
      auto globalObject = JSContextGetGlobalObject(m_context);
      String jsPropertyName(propName.c_str());
    
      String jsValueJSON(jsonValue.c_str());
      auto valueToInject = JSValueMakeFromJSONString(m_context, jsValueJSON);
    
      JSObjectSetProperty(m_context, globalObject, jsPropertyName, valueToInject, 0, NULL);
    }
    

    我们这里必须要给大家解释一个东西也就是JavaScriptCore,我们知道JavaScript是解释执行的,他的执行引擎在Android默认的就是JavaScriptCore,而JavaScriptCore在Android架构中就是在framework层,基本上是C/C++实现,另外JavaScriptCore为了外部环境能够执行JavaScript提供了一套API接口给外部去动态执行JavaScript,这也是一套C++接口,这也是我们为什么要进入JNI的原因,而我们刚刚看到的 JSContextGetGlobalObjectJSObjectSetProperty 就是两个JavaScriptCore的API的两个暴露出来的接口

    现在我们知道了JSCExecutor::setGlobalVariable最后给JS的全局变量设置一个属性__fbBatchedBridgeConfig,这个属性的值就是JavaScriptModule,接着再看下callFunction:

    //jni/react/JSCExecutor.cpp
    std::string JSCExecutor::callFunction(const double moduleId, const double methodId, const folly::dynamic& arguments) {
      // TODO:  Make this a first class function instead of evaling. #9317773
      std::vector<folly::dynamic> call{
        (double) moduleId,
        (double) methodId,
        std::move(arguments),
      };
      return executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
    }
    
    static std::string executeJSCallWithJSC(
        JSGlobalContextRef ctx,
        const std::string& methodName,
        const std::vector<folly::dynamic>& arguments) {
      #ifdef WITH_FBSYSTRACE
      FbSystraceSection s(
          TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.executeJSCall",
          "method", methodName);
      #endif
    
      // Evaluate script with JSC
      folly::dynamic jsonArgs(arguments.begin(), arguments.end());
      auto js = folly::to<folly::fbstring>(
          "__fbBatchedBridge.", methodName, ".apply(null, ",
          folly::toJson(jsonArgs), ")");
      auto result = evaluateScript(ctx, String(js.c_str()), nullptr);
      return Value(ctx, result).toJSONString();
    }
    

    __fbBatchedBridge.callFunctionReturnFlushedQueue.apply(null,{moduleId, methodId, arguments})的形式拼接一个apply的Javascript执行语句,最后调用的evaluateScript的来执行这个语句,完成Bridge向Javascript的调用,而evaluateScript又是一个JavaScriptCore暴露出来的API,他的作用就是执行一段JavaScript代码

    来看一下JS层的BatchedBridge.js:

    //Libraries/BatchedBridge/BatchedBridge.js
    const MessageQueue = require('MessageQueue');
    
    const BatchedBridge = new MessageQueue(
      __fbBatchedBridgeConfig.remoteModuleConfig,   //Native(Java)模块
      __fbBatchedBridgeConfig.localModulesConfig,   //JS模块
    );
    
    // TODO: Move these around to solve the cycle in a cleaner way.
    
    const Systrace = require('Systrace');
    const JSTimersExecution = require('JSTimersExecution');
    
    BatchedBridge.registerCallableModule('Systrace', Systrace);
    BatchedBridge.registerCallableModule('JSTimersExecution', JSTimersExecution);
    
    if (__DEV__) {
      BatchedBridge.registerCallableModule('HMRClient', require('HMRClient'));
    }
    
    Object.defineProperty(global, '__fbBatchedBridge', { value: BatchedBridge });
    
    module.exports = BatchedBridge;
    

    我们再来看看JavaScript端:刚才我们分析了由于__fbBatchedBridgeConfig对象是被直接定义成Global全局对象的属性,类似于window对象,__fbBatchedBridgeConfig对象里又有两个属性:remoteModuleConfig和localModulesConfig,分别对应Java模块和JS模块。而且还看到了定义了另一个全局属性:__fbBatchedBridge,而这个全局属性的值就是MessageQueue对象

    我们上文提到的 __fbBatchedBridge.callFunctionReturnFlushedQueue.apply(null,{moduleId, methodId, arguments}) 这个表达式里面__fbBatchedBridge就是他在这里赋的值

    我们再看看callFunctionReturnFlushedQueue函数:

    class MessageQueue {
    
     constructor(remoteModules, localModules) {
       this.RemoteModules = {};
    
       this._callableModules = {};
       this._queue = [[], [], [], 0];
       this._moduleTable = {};
       this._methodTable = {};
       this._callbacks = [];
       this._callbackID = 0;
       this._callID = 0;
       this._lastFlush = 0;
       this._eventLoopStartTime = new Date().getTime();
    
       [
         'invokeCallbackAndReturnFlushedQueue',
         'callFunctionReturnFlushedQueue',
         'flushedQueue',
       ].forEach((fn) => this[fn] = this[fn].bind(this));
    
       let modulesConfig = this._genModulesConfig(remoteModules);
       this._genModules(modulesConfig);
       localModules && this._genLookupTables(
         this._genModulesConfig(localModules),this._moduleTable, this._methodTable
       );
    
       this._debugInfo = {};
       this._remoteModuleTable = {};
       this._remoteMethodTable = {};
       this._genLookupTables(
         modulesConfig, this._remoteModuleTable, this._remoteMethodTable
       );
     }
    
     /**
      * Public APIs
      */
     callFunctionReturnFlushedQueue(module, method, args) {
       guard(() => {
         this.__callFunction(module, method, args);
         this.__callImmediates();
       });
    
       return this.flushedQueue();
     }
     
     _genLookupTables(modulesConfig, moduleTable, methodTable) {
       modulesConfig.forEach((config, moduleID) => {
         this._genLookup(config, moduleID, moduleTable, methodTable);
       });
     }
    
     _genLookup(config, moduleID, moduleTable, methodTable) {
       if (!config) {
         return;
       }
    
       let moduleName, methods;
       if (moduleHasConstants(config)) {
         [moduleName, , methods] = config;
       } else {
         [moduleName, methods] = config;
       }
    
       moduleTable[moduleID] = moduleName;
       methodTable[moduleID] = Object.assign({}, methods);
     }
    }
    
    module.exports = MessageQueue;
    

    里面__callFunction是最后一步了:

     __callFunction(module: string, method: string, args: any[]): void {
        this._lastFlush = Date.now();
        this._eventLoopStartTime = this._lastFlush;
        if (__DEV__ || this.__spy) {
          Systrace.beginEvent(`${module}.${method}(${stringifySafe(args)})`);
        } else {
          Systrace.beginEvent(`${module}.${method}(...)`);
        }
        if (this.__spy) {
          this.__spy({type: TO_JS, module, method, args});
        }
        const moduleMethods = this.getCallableModule(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,
        );
        moduleMethods[method].apply(moduleMethods, args);
        Systrace.endEvent();
      }
    

    相信大家对其中 moduleMethods[method].apply(moduleMethods, args); 这句话应该不陌生,大意就是运行moduleMethods的method方法,而moduleMethods又是怎么来的呢:const moduleMethods = this.getCallableModule(module);

      getCallableModule(name: string): any | null {
        const getValue = this._lazyCallableModules[name];
        return getValue ? getValue() : null;
      }
    

    而_lazyCallableModules又是谁添加的呢,你可以这样理解,每一个想暴露的给Native的模块都会注册添加,当然也包括我们上面分析的RCTEventEmitter,我们看看RCTEventEmitter.js

    //Libraries/BatchedBridge/BatchedBridgedModules/RCTEventEmitter.js
    var BatchedBridge = require('BatchedBridge');
    var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
    
    BatchedBridge.registerCallableModule(
      'RCTEventEmitter',
      ReactNativeEventEmitter
    );
    
    // Completely locally implemented - no native hooks.
    module.exports = ReactNativeEventEmitter;
    

    其中registerCallableModule很简单就是往_lazyCallableModules去添加对象:

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

    我们再来看看我们在JAVA方法中使用的emit函数对应是怎么执行的啊

    ...
    import com.facebook.react.modules.core.DeviceEventManagerModule;
    import com.facebook.react.bridge.WritableMap;
    import com.facebook.react.bridge.Arguments;
    ...
    private void sendEvent(ReactContext reactContext,
                           String eventName,
                           @Nullable WritableMap params) {
      reactContext
          .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
          .emit(eventName, params);
    }
    ...
    WritableMap params = Arguments.createMap();
    params.putString("eventProperty", "someValue");
    ...
    sendEvent(reactContext, "EventReminder", params);
    

    对应的JavaScript端:

      emit(eventType: string) {
        const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
        if (subscriptions) {
          for (let i = 0, l = subscriptions.length; i < l; i++) {
            const subscription = subscriptions[i];
    
            // The subscription may have been removed during this event loop.
            if (subscription && subscription.listener) {
              this._currentSubscription = subscription;
              subscription.listener.apply(
                subscription.context,
                Array.prototype.slice.call(arguments, 1),
              );
            }
          }
          this._currentSubscription = null;
        }
      }
    

    稍微解释一下,大致就是通过eventType去或者一个或多个订阅者,然后遍历这些订阅者里面的subscription.listener,然后通过下面的语句去执行这些早就注册的listener

    subscription.listener.apply(
                subscription.context,
                Array.prototype.slice.call(arguments, 1),
              ); 
    

    最后上一段代码给大家回忆下JavaScript段怎么使用EventEmitter的

    import { NativeEventEmitter, NativeModules } from 'react-native';
    // ...
    
      componentDidMount() {
        // ...
        const eventEmitter = new NativeEventEmitter(NativeModules.ToastExample);
        this.eventListener = eventEmitter.addListener('EventReminder', (event) => {
           console.log(event.eventProperty) // "someValue"
        };
        // ...
      }
      componentWillUnmount() {
        this.eventListener.remove(); // 组件卸载时记得移除监听事件
      }
    

    通过addListener来注册一个监听函数等待JAVA端的调用,里面的第一个参数就是订阅者的名字,第二个参数就是订阅者要执行的方法

    既然都说到这里了,我们就再给大家把最后的调用关系串起来再分析下吧,JAVA端我们再看看这个发送事件的函数:

      reactContext
          .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
          .emit(eventName, params);
    

    reactContext就是一个ReactContext对象,再看看他的getJSModule方法是什么呢:

      /**
       * @return handle to the specified JS module for the CatalystInstance associated with this Context
       */
      public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
        if (mCatalystInstance == null) {
          if (mDestroyed) {
            throw new IllegalStateException(LATE_JS_ACCESS_EXCEPTION_MESSAGE);
          }
          throw new IllegalStateException(EARLY_JS_ACCESS_EXCEPTION_MESSAGE);
        }
        return mCatalystInstance.getJSModule(jsInterface);
      }
    

    就是调用了 mCatalystInstance.getJSModule(jsInterface); 去获取一个JavaScriptModule,mCatalystInstance其实是一个CatalystInstanceImpl的对象,再看看他的getJSModule方法是什么:

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

    mJSModuleRegistry就是上面我们提及的JavaScriptModuleRegistry对象,大家可以往上翻翻,这个就是调用到了他的getJavaScriptModule方法返回了一个动态代理产生的JavaScriptModule对象,这样的话所有的调用都形成了一个闭环了

    我们最后用几句话来总结整个调用过程来帮助大家总结下:

    • 一开始所有的NativeModule和JSModule在ReactInstanceManagerImpl中注册,所有的JavaScriptModules,并且都扫描存放在JavaScriptModulesConfig中,ReactInstanceManagerImpl将JavaScriptModulesConfig用来实例化catalystInstance;

    • catalystInstance的buildModulesConfigJSONProperty方法把JavaScriptModulesConfig,NativeModuleRegistry(所有的JavaScriptModule与NativeModule)都写入了__fbBatchedBridgeConfig全局对象里的两个属性:remoteModuleConfig和localModulesConfig,分别对应Java模块和JS模块,并且把这个通过Webkit的接口属性注入到了C++层的里面方便调用(因为JavaScript最终执行是在C++层,因为Android里面的WebKit,JavaScriptCore是在library的C++层,写入的是通过JavascriptCore提供接口实现)

    • Java调用JS方法时统一分发到JavaScriptModuleInvocationHandler中的invoke进行处理,在invoke中其实就是调用mCatalystInstance.callFunction->ReactBridge.callFunction->最终__fbBatchedBridge.callFunctionReturnFlushedQueue.apply(null,{moduleId, methodId, arguments})的形式拼接一个apply的Javascript执行语句,最后调用jni/react/JSCHelpers.cpp的evaluateScript来执行(最终调用到JavascriptCore来执行这句JS)

    • JS端的__fbBatchedBridge就是BatchedBridge的属性,BatchedBridge就是一个MessageQueue对象,他在初始化的时候存放了__fbBatchedBridgeConfig的remoteModuleConfig(Native模块)与localModulesConfig(JS模块)最后调用到this.__callFunction(module, method, args)里面的moduleMethods[method].apply(moduleMethods, args)来进行调用,moduleMethods的来源就是被调用的JavaScript层通过registerCallableModule方法写入的属性(实现Native到JavaScript步骤里面JS的模块会做这个步骤)

    好了,我们介绍的ReactNative Android 运行原理之<JAVA TO JavaScript>就告一段落了,里面涉及额部分代码有些是新版本的大家可能有点对不上,但是大致理解里面的思路就行,我们下一篇介绍 ReactNative Android 运行原理之<JavaScript TO JAVA>,欢迎敬请期待···

    相关文章

      网友评论

          本文标题:ReactNative Android 运行原理之

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