React Native与Android通信——Android calls JS(上)0.45

示例

首先创建一个简单的react native for android项目,添加两个为JS Moudule和Native Module的类,分别为TestModuleManager和MyNativeModule:

1      package com.example.testing.myproject2.jsmodule;2      3      import com.facebook.react.bridge.JavaScriptModule;4      5      public interface TestModuleManager extends JavaScriptModule {6          void callScript(int value);7      }
1      package com.example.testing.myproject2.nativemodule;2      3      import com.example.testing.myproject2.jsmodule.TestModuleManager;4      import com.facebook.react.bridge.ReactApplicationContext;5      import com.facebook.react.bridge.ReactContextBaseJavaModule;6      7      import java.util.Timer;8      import java.util.TimerTask;9      10     public class MyNativeModule extends ReactContextBaseJavaModule {11     12         private int value = 100;13     14         public MyNativeModule(final ReactApplicationContext reactContext) {15             super(reactContext);16             new Timer().schedule(new TimerTask() {17                 @Override18                 public void run() {19                     reactContext.getJSModule(TestModuleManager.class).callScript(value++);20                 }21             }, 1000, 1000);22         }23     24         @Override25         public String getName() {26             return "MyNativeModule";27         }28     }

将MyNativeModule添加到你自定义的ReactPacakge中,再于js目录下,新建TestModuleManager.js

1      /**2       * @providesModule TestModuleManager3       */4      5      import BatchedBridge from 'BatchedBridge'6      class TestModuleManager {7          callScript(value) {8              console.log("value: " + value);9          }10     }11     let TestModuleManagerInstance = new TestModuleManager();12     BatchedBridge.registerCallableModule("TestModuleManager", TestModuleManagerInstance);13     export default TestModuleManagerInstance;

运行程序,终端在react native目录下输入react-native log-android,你应该能在看到不断打印出value的值:

接下来,我们对android to js的通信过程进行解析。在分析之前,你需要保证你的项目已经编译了react native源码(或者拥有react native的源码),版本为0.45.1,并且你对于java和js的语法有所了解。
开始之前,先解释名词:
Native:Android

解析

reactContext.getJSModule(TestModuleManager.class).callScript(value++);

本文的最终目的,是为了解释上面这一句代码,了解react native中,android调用js模块的具体流程。基于此,我们先提出这样一个问题:

问题一:getJSModule是由reactContext调用的吗?

先看看getJSModule方法:

1        public  T getJSModule(Class jsInterface) {2          if (mCatalystInstance == null) {3            throw new RuntimeException(EARLY_JS_ACCESS_EXCEPTION_MESSAGE);4          }5          return mCatalystInstance.getJSModule(jsInterface);6        }

getJSModule本质上是调用了mCatalystInstance的getJSModule方法,传入的参数是jsInterface,也就是我们需要调用的JS模块,在NATIVE中表现为接口(MyModuleManager.java)。

答案一:getJSModule是由mCatalystInstance调用的,入参为我们声明的JS模块接口
问题二:mCatalystInstance是类还是接口?

下面是我们自定义的JS模块接口

public interface MyModuleManager extends JavaScriptModule

在ReactContext.java中,再看mCatalystInstance

private @Nullable CatalystInstance mCatalystInstance;
public interface CatalystInstance extends MemoryPressureListener, JSInstance

很明显mCatalystInstance是个接口,我们先查找它的实现类。

答案二:mCatalystInstance是接口
问题三:mCatalystInstance的实现类是哪个类?

在ReactContext中,有这么一个方法:

1      public void initializeWithInstance(CatalystInstance catalystInstance) {2        if (catalystInstance == null) {3          throw new IllegalArgumentException("CatalystInstance cannot be null.");4        }5        if (mCatalystInstance != null) {6          throw new IllegalStateException("ReactContext has been already initialized");7        }8      9        mCatalystInstance = catalystInstance;10     11       ReactQueueConfiguration queueConfig = catalystInstance.getReactQueueConfiguration();12       mUiMessageQueueThread = queueConfig.getUIQueueThread();13       mUiBackgroundMessageQueueThread = queueConfig.getUIBackgroundQueueThread();14       mNativeModulesMessageQueueThread = queueConfig.getNativeModulesQueueThread();15       mJSMessageQueueThread = queueConfig.getJSQueueThread();16     }

第9行,mCatalystInstance被赋值,我们全局搜索initializeWithInstance被调用的地方,正是在ReactInstanceManager.java内。

1      private ReactApplicationContext createReactContext(2              JavaScriptExecutor jsExecutor,3              JSBundleLoader jsBundleLoader) {4          FLog.i(ReactConstants.TAG, "Creating react context.");5          ReactMarker.logMarker(CREATE_REACT_CONTEXT_START);6          final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);7          NativeModuleRegistryBuilder nativeModuleRegistryBuilder = new NativeModuleRegistryBuilder(8                  reactContext,9                  this,10                 mLazyNativeModulesEnabled);11         JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder();12         if (mUseDeveloperSupport) {13             reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);14         }15     16         ReactMarker.logMarker(PROCESS_PACKAGES_START);17         Systrace.beginSection(18                 TRACE_TAG_REACT_JAVA_BRIDGE,19                 "createAndProcessCoreModulesPackage");20         try {21             CoreModulesPackage coreModulesPackage =22                     new CoreModulesPackage(23                             this,24                             mBackBtnHandler,25                             mUIImplementationProvider,26                             mLazyViewManagersEnabled);27             processPackage(coreModulesPackage, nativeModuleRegistryBuilder, jsModulesBuilder);28         } finally {29             Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);30         }31     32         // TODO(6818138): Solve use-case of native/js modules overriding33         for (ReactPackage reactPackage : mPackages) {34             Systrace.beginSection(35                     TRACE_TAG_REACT_JAVA_BRIDGE,36                     "createAndProcessCustomReactPackage");37             try {38                 processPackage(reactPackage, nativeModuleRegistryBuilder, jsModulesBuilder);39             } finally {40                 Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);41             }42         }43         ReactMarker.logMarker(PROCESS_PACKAGES_END);44     45         ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START);46         Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry");47         NativeModuleRegistry nativeModuleRegistry;48         try {49             nativeModuleRegistry = nativeModuleRegistryBuilder.build();50         } finally {51             Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);52             ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END);53         }54     55         NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null56                 ? mNativeModuleCallExceptionHandler57                 : mDevSupportManager;58         CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()59                 .setReactQueueConfigurationSpec(mUseSeparateUIBackgroundThread ?60                         ReactQueueConfigurationSpec.createWithSeparateUIBackgroundThread() :61                         ReactQueueConfigurationSpec.createDefault())62                 .setJSExecutor(jsExecutor)63                 .setRegistry(nativeModuleRegistry)64                 .setJSModuleRegistry(jsModulesBuilder.build())65                 .setJSBundleLoader(jsBundleLoader)66                 .setNativeModuleCallExceptionHandler(exceptionHandler);67     68         ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);69         // CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp70         Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");71         final CatalystInstance catalystInstance;72         try {73             catalystInstance = catalystInstanceBuilder.build();74         } finally {75             Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);76             ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);77         }78     79         if (mBridgeIdleDebugListener != null) {80             catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);81         }82         if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JSC_CALLS)) {83             catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");84         }85     86         reactContext.initializeWithInstance(catalystInstance);87         ReactMarker.logMarker(ReactMarkerConstants.PRE_RUN_JS_BUNDLE_START);88         catalystInstance.runJSBundle();89     90         return reactContext;91     }

在ReactInstanceManagerImpl的createReactContext方法的第86行,的确有这么一句

reactContext.initializeWithInstance(catalystInstance);

在第71-77行,则是给catalysInstance赋值

 final CatalystInstance catalystInstance;        try {            catalystInstance = catalystInstanceBuilder.build();        } finally {            Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);            ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);        }

我们看CatalystInstanceImpl.Builder类的build()方法:

        public CatalystInstanceImpl build() {            return new CatalystInstanceImpl(                    Assertions.assertNotNull(mReactQueueConfigurationSpec),                    Assertions.assertNotNull(mJSExecutor),                    Assertions.assertNotNull(mRegistry),                    Assertions.assertNotNull(mJSModuleRegistry),                    Assertions.assertNotNull(mJSBundleLoader),                    Assertions.assertNotNull(mNativeModuleCallExceptionHandler));        }

build()返回的是CatalystInstanceImpl,整个流程是catalystInstanceBuilder.build()->reactContext.initializeWithInstance(catalystInstance)->mCatalystInstance=catalystInstance->mCatalystInstance.getJSModule(jsInterface)

这样就清楚了,mCatalystInstance的实现类是CatalystInstanceImpl

答案三:mCatalystInstance的实现类是CatalystInstanceImpl
问题四:CatalystInstanceImpl的getJSModule究竟是返回了哪个类,使得mCatalystInstance.getJSModule(jsInterface)可以调用callScript()

为了解决问题四,我们看CatalystInstanceImplgetJSModule

1      @Override2      public  T getJSModule(Class jsInterface) {3        return mJSModuleRegistry.getJavaScriptModule(this, jsInterface);4      }

getJSModule实际是调用了mJSModuleRegistrygetJavaScriptModule方法,传入两个参数,第一个是this,它正是CatalystInstanceImpl的当前实例,第二个则是自定义的JS模块

我们看看getJavaScriptModule方法,它在JavaScriptModuleRegistry内:

1      public synchronized  T getJavaScriptModule(2          CatalystInstance instance,3          Class moduleInterface) {4        JavaScriptModule module = mModuleInstances.get(moduleInterface);5        if (module != null) {6          return (T) module;7        }8      9        JavaScriptModuleRegistration registration =10           Assertions.assertNotNull(11               mModuleRegistrations.get(moduleInterface),12               "JS module " + moduleInterface.getSimpleName() + " hasn't been registered!");13       JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(14           moduleInterface.getClassLoader(),15           new Class[]{moduleInterface},16           new JavaScriptModuleInvocationHandler(instance, registration));17       mModuleInstances.put(moduleInterface, interfaceProxy);18       return (T) interfaceProxy;19     }

该方法主要做了以下几步:

4        JavaScriptModule module = mModuleInstances.get(moduleInterface);5        if (module != null) {6          return (T) module;7        }
  private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;

第4-7行:用mModuleInstance得到指定JS模块,mModuleInstance本质上是存储JS模块的HashMap。如果module不为空,表示之前已经存有该对应模块,直接返回实例对象,并强转为指定的泛型类,其实就是我们一开始传入的TestModuleManager类。拿到实例对象,我们自然能调用对应的接口方法callScript()。但是,我们在TestModuleManager中声明的callScript只是接口方法,方法内容是由具体的实现类实现的吗?如果是的话,方法内容到底是什么呢?真正的实例到底在哪里?三个问题所指向的最终答案,就在9-18行中。

答案四:CatalystInstanceImpl的getJSModule返回的是调用JS模块的实例对象,因此能调用callScript()方法
问题五:callScript是接口方法,执行的内容是什么?

9        JavaScriptModuleRegistration registration =10           Assertions.assertNotNull(11               mModuleRegistrations.get(moduleInterface),12               "JS module " + moduleInterface.getSimpleName() + " hasn't been registered!");13       JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(14           moduleInterface.getClassLoader(),15           new Class[]{moduleInterface},16           new JavaScriptModuleInvocationHandler(instance, registration));17       mModuleInstances.put(moduleInterface, interfaceProxy);18       return (T) interfaceProxy;

第9-18行:之前不存在对应JS模块,则会进入这里。第9行创建了JavaScriptModuleRegistration对象registration。第11行mModuleRegistrations.get(moduleInterface)取到指定JS模块的JavaScriptModuleRegistration实例。说到底,前面讲的都是废话,最重要的是第13行。看到没,有句Proxy.newProxyInstance,对于熟练Java语言的对该句的设计模式理应是很熟悉了,正是动态代理。需要动态代理的类就是我们JS模块的接口,而Handler则是JavaScriptModuleInvocationHandler。当创建完动态代理的对象后,会将该对象put到mModuleInstances中。mModuleInstances不就是第4行试图取出指定JS模块接口的HashMap吗?而我们put进去后,第4行自然就能取出了。取出来的对象,显然就是动态代理对象,也就是实现了JS模块接口的对象实例。

到目前为止,我们仅仅知道调用callScript方法的流程,却还不知道callScript方法的内容。不过,既然知道使用动态代理方式来生成JS模块的实例对象,接下来要做的事情就清晰多了——查看动态代理对象Handler的实际代理内容,也就是JavaScriptModuleInvocationHandler的invoke方法。

1      private static class JavaScriptModuleInvocationHandler implements InvocationHandler {2        private final CatalystInstance mCatalystInstance;3        private final JavaScriptModuleRegistration mModuleRegistration;4      5        public JavaScriptModuleInvocationHandler(6            CatalystInstance catalystInstance,7            JavaScriptModuleRegistration moduleRegistration) {8          mCatalystInstance = catalystInstance;9          mModuleRegistration = moduleRegistration;10       }11     12       @Override13       public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {14         NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();15         mCatalystInstance.callFunction(16           mModuleRegistration.getName(),17           method.getName(),18           jsArgs19         );20         return null;21       }22     }

主要关注的是第13行开始的invoke方法。当调用callScript的时候,会进入到此方法中进行预处理。
若是像一般的动态代理,应当会使用method.invoke来调用代理接口的实现。但是react native for android显然没有这么做。第15行开始,调用的便是mCatalystInstance的callFunction方法。而mCatalystInstance之前讨论过,它的实现类是CatalystInstanceImpl。这么看来,callScript()执行的”实际内容”为CatalystInstanceImpl的callFunction方法,而不是实现其对应的接口。

答案五:callScript本身并不执行,而是通过动态代理的方式,执行CatalystInstanceImpl的callFunction方法
问题六:CatalystInstanceImpl的callFunction方法到底执行了什么?

观察第15行,发现传入了三个参数:包装我们JS模块接口的JavaScriptModuleRegistration(只要知道在添加JavaScriptModule到我们Package中的时候,它会被包装被JavaScriptModuleRegistration,且JavaScriptModuleRegistration持有JavaScriptModule类实例(.class对象)和声明的所有接口方法即可,具体原理不加以讨论)的方法getName(第一个参数),method的名字(第二个参数),以及method参数(第三个参数),对应于我们JS模块,三个参数分别为模块名TestModuleManager、方法名callScript,传入的整形参数value(值从100递增)。

我们看看CatalystInstanceImpl的callFunction方法

1      @Override2      public void callFunction(3          final String module,4          final String method,5          final NativeArray arguments) {6        if (mDestroyed) {7          FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed.");8          return;9        }10       if (!mAcceptCalls) {11         // Most of the time the instance is initialized and we don't need to acquire the lock12         synchronized (mJSCallsPendingInitLock) {13           if (!mAcceptCalls) {14             mJSCallsPendingInit.add(new PendingJSCall(module, method, arguments));15             return;16           }17         }18       }19     20       jniCallJSFunction(module, method, arguments);21     }

第6-18行执行的都是一些判断,我们直接看第21行的jniCallJSFunction,它同样是传入了之前提到的三个参数。

1      private native void jniCallJSFunction(2        String module,3        String method,4        NativeArray arguments);

jniCallJSFunction有native声明,看来是c++的函数!我们全局搜索jniCallJSFunction,得到以下代码,其实CatalystInstanceImpl的jniCallJSFunction实际调用的是Instance的callJSFunction函数。

void CatalystInstanceImpl::jniCallJSFunction(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(std::move(module),                            std::move(method),                            arguments->consume());}

答案六:CatalystInstanceImpl的callFunction最终执行了Instance类下的callJSFunction方法,而该方法为c++方法。
问题七:Instance中的callJSFunction到底执行了什么?

既然知道最终执行了c++中的jniCallJSFunction,那我们看看它到底干了什么。
搜索到该方法在Instance.cpp中。为了分析方便,我们一次性将其涉及到的所有文件的特定内容都列出来。

1      void Instance::callJSFunction(std::string&& module, std::string&& method, folly::dynamic&& params) {2        callback_->incrementPendingJSCalls();3        nativeToJsBridge_->callFunction(std::move(module), std::move(method), std::move(params));4      }5      ---------------------------------------------------------------------------------------------------------------------------------------6      void NativeToJsBridge::callFunction(7          std::string&& module,8          std::string&& method,9          folly::dynamic&& arguments) {10       int systraceCookie = -1;11       #ifdef WITH_FBSYSTRACE12       systraceCookie = m_systraceCookie++;13       std::string tracingName = fbsystrace_is_tracing(TRACE_TAG_REACT_CXX_BRIDGE) ?14         folly::to<std::string>("JSCall__", module, '_', method) : std::string();15       SystraceSection s(tracingName.c_str());16       FbSystraceAsyncFlow::begin(17           TRACE_TAG_REACT_CXX_BRIDGE,18           tracingName.c_str(),19           systraceCookie);20       #else21       std::string tracingName;22       #endif23     24       runOnExecutorQueue([module = std::move(module), method = std::move(method), arguments = std::move(arguments), tracingName = std::move(tracingName), systraceCookie]25         (JSExecutor* executor) {26           #ifdef WITH_FBSYSTRACE27           FbSystraceAsyncFlow::end(28               TRACE_TAG_REACT_CXX_BRIDGE,29               tracingName.c_str(),30               systraceCookie);31           SystraceSection s(tracingName.c_str());32           #endif33     34           // This is safe because we are running on the executor's thread: it won't35           // destruct until after it's been unregistered (which we check above) and36           // that will happen on this thread37           executor->callFunction(module, method, arguments);38         });39     }40     ---------------------------------------------------------------------------------------------------------------------------------------41     void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {42       SystraceSection s("JSCExecutor::callFunction");43       // This weird pattern is because Value is not default constructible.44       // The lambda is inlined, so there's no overhead.45     46       auto result = [&] {47         try {48           if (!m_callFunctionReturnResultAndFlushedQueueJS) {49             bindBridge();50           }51           return m_callFunctionReturnFlushedQueueJS->callAsFunction({52             Value(m_context, String::createExpectingAscii(m_context, moduleId)),53             Value(m_context, String::createExpectingAscii(m_context, methodId)),54             Value::fromDynamic(m_context, std::move(arguments))55           });56         } catch (...) {57           std::throw_with_nested(58             std::runtime_error("Error calling " + moduleId + "." + methodId));59         }60       }();61     62       callNativeModules(std::move(result));63     }64     ---------------------------------------------------------------------------------------------------------------------------------------65     void JSCExecutor::bindBridge() throw(JSException) {66       SystraceSection s("JSCExecutor::bindBridge");67       std::call_once(m_bindFlag, [this] {68         auto global = Object::getGlobalObject(m_context);69         auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");70         if (batchedBridgeValue.isUndefined()) {71           auto requireBatchedBridge = global.getProperty("__fbRequireBatchedBridge");72           if (!requireBatchedBridge.isUndefined()) {73             batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({});74           }75           if (batchedBridgeValue.isUndefined()) {76             throwJSExecutionException("Could not get BatchedBridge, make sure your bundle is packaged correctly");77           }78         }79     80         auto batchedBridge = batchedBridgeValue.asObject();81         m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();82         m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject();83         m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();84         m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue").asObject();85       });86     }

第2行:调用的是Native的方法,具体实现是:取出一个正在等待的JS调用,并让JS调用的个数减一。因为不在本文的讨论范围,所有不深入解释。(具体可查看关于react native android启动流程的文章)
第3行:调用了NativeToJsBridge的callFunction方法。看来是一层调用,指向第6行。

答案七:Instance中的callJSFunction调用了NativeToJsBridge的callFunction函数。
问题八:NativeToJsBridge的callFunction函数到底执行了什么?

第10-32行:执行栈跟踪等任务,与讨论无关,忽略
第37行:又是一层调用,由JSCExecutor的callFunction执行(executor是JSExecutor的实例,但JSExecutor是虚基类,由JSCExecutor继承),传入参数分别为模块名,方法名和参数,指向第41行。

答案八:NativeToJsBridge的callFunction函数调用了JSCExecutor的callFunction。
问题九:JSCExecutor的callFunction函数到底执行了什么?

第46-60行:实际关注为51-55行。它将我们传入的参数传给了m_callFunctionReturnFlushedQueueJS的函数callAsFunction。传入前,模块名和方法名(类型都是String)都用Value初始化。初始化后的类型是OpaqueJSValue,对应JS中的一个对象(JS中是以多态函数的方式实现的),而参数名由fromDynamic初始化。fromDynamic将参数转为Json对象,再传给Value初始化为OpaqueJSValue。总之,我们传入的参数,都已经转为相应的JS对象。这些对象最终都会传给m_callFunctionReturnFlushedQueueJS的函数callAsFunction,指向从65行开始的函数。

第62行:获得JS函数调用后的结果,也就是callScript的返回值,并传给Native进行处理。但是,m_callFunctionReturnFlushedQueueJS并不会返回值,也就是result一直为null。如果需要有返回值,则要调用m_callFunctionReturnFlushedQueueJSAndFlushQueue函数。况且,由于这一块是JS calls Native,而我们本文的主题是Native calls Js,所以不加以讨论。

答案九:JSCExecutor的callFunction函数将模块名、方法名和参数都转为Value类实例,作为新的参数传递给m_callFunctionReturnFlushedQueueJS的函数callAsFunction。
问题十:m_callFunctionReturnFlushedQueueJS的callAsFunction函数到底执行了什么?

m_callFunctionReturnFlushedQueueJS在JSCExecutor.c中完成了初始化,初始化的内容就在第69行开始的bindBridge()内。

第81行:m_callFunctionReturnFlushedQueueJS被初始化。初始化的实质,由JSC调用batchedBridgeValue所属类的callFunctionReturnFlushedQueue对象完成。而batchedBridgeValue是哪个类?答案已经很明显了,就是JSC引用的类,也就是我们在JS端定义的全局对象。所以,最后调用的是JS对象。那么,JSC引用的类是哪个类?第80行,可以得知batchedBridgeValue由batchedBridgeValue的asObject生成。第69行,由JS定义的__fbBatchedBridge属性生成。__fbBatchedBridge属性定义的是哪个类?就在下面的代码里。

1      Object.defineProperty(global, '__fbBatchedBridge', {2        configurable: true,3        value: BatchedBridge,4      });

上面四行简单的代码,就在JS类BatchedBridge.js中。之后的分析你将明白,BatchedBridge不过是JS中MessageQueue的一个实例对象。

答案十:m_callFunctionReturnFlushedQueueJS的callAsFunction函数调用JS的定义的全局对象BatchedBridge所属函数callFunctionReturnFlushedQueue。

至此,所有的调用关系都连接完成。在Native中我们调用的callScript()方法,通过动态代理的方式,最终会走到c++中的CatalystInstanceImpl类中的CallJSFunction完成。c++中的CatalystInstanceImpl类中的CallJSFunction,又会执行到JSCExecutor的callFunction函数,调用JS对象BatchedBridge的callFunctionReturnFlushedQueue函数。

通过猜测我们也能知晓,callFunctionReturnFlushedQueue会调用我们在JS端定义的函数。那么JS具体调用过程如何?又会遇到什么样的阻碍呢?我们下文待续。

更多相关文章

  1. C语言函数以及函数的使用
  2. 选项卡使用方法二(Android学习随笔十三)
  3. 使用AndroidStudio编译NDK的方法及错误解决方式
  4. Android Studio 配置快捷方式生成JNI头文件的方法
  5. android 读取DDMS里的文件时打不开,解决方法
  6. Android:Manifest merger failed with multiple errors, see log
  7. android中真正destroy掉activity的方法
  8. Android旋转屏幕不销毁数据的方法
  9. Android程序设置成横屏方法

随机推荐

  1. android开发学习资料
  2. Android之在Bitmap上涂鸦效果
  3. android 自定义 checkbox
  4. android 塔防游戏汇总 及android 游戏开
  5. 好的网子
  6. android 制作自定义标题栏
  7. android删除sd卡文件
  8. Android生命周期
  9. Android(安卓)使用SeekBar 变更屏幕亮度
  10. Android的一些例子