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

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                 @Override
18                 public void run() {
19                     reactContext.getJSModule(TestModuleManager.class).callScript(value++);
20                 }
21             }, 1000, 1000);
22         }
23     
24         @Override
25         public String getName() {
26             return "MyNativeModule";
27         }
28     }

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

1      /**
2       * @providesModule TestModuleManager
3       */
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 overriding
33         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 != null
56                 ? mNativeModuleCallExceptionHandler
57                 : 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.cpp
70         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      @Override
2      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       @Override
13       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           jsArgs
19         );
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      @Override
2      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 lock
12         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_FBSYSTRACE
12       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       #else
21       std::string tracingName;
22       #endif
23     
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_FBSYSTRACE
27           FbSystraceAsyncFlow::end(
28               TRACE_TAG_REACT_CXX_BRIDGE,
29               tracingName.c_str(),
30               systraceCookie);
31           SystraceSection s(tracingName.c_str());
32           #endif
33     
34           // This is safe because we are running on the executor's thread: it won't
35           // destruct until after it's been unregistered (which we check above) and
36           // that will happen on this thread
37           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具体调用过程如何?又会遇到什么样的阻碍呢?我们下文待续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值