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()
为了解决问题四,我们看CatalystInstanceImpl
的getJSModule
1 @Override
2 public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
3 return mJSModuleRegistry.getJavaScriptModule(this, jsInterface);
4 }
getJSModule
实际是调用了mJSModuleRegistry
的getJavaScriptModule
方法,传入两个参数,第一个是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具体调用过程如何?又会遇到什么样的阻碍呢?我们下文待续。