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

来源:互联网 发布:无缝拼图软件四宫格 编辑:程序博客网 时间:2024/05/21 10:07

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 extends JavaScriptModule> T getJSModule(Class<T> 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 extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {3        return mJSModuleRegistry.getJavaScriptModule(this, jsInterface);4      }

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

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

1      public synchronized <T extends JavaScriptModule> T getJavaScriptModule(2          CatalystInstance instance,3          Class<T> 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具体调用过程如何?又会遇到什么样的阻碍呢?我们下文待续。

阅读全文
0 0
原创粉丝点击