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 @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()
为了解决问题四,我们看CatalystInstanceImpl
的getJSModule
1 @Override2 public T getJSModule(Class jsInterface) {3 return mJSModuleRegistry.getJavaScriptModule(this, jsInterface);4 }
getJSModule
实际是调用了mJSModuleRegistry
的getJavaScriptModule
方法,传入两个参数,第一个是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具体调用过程如何?又会遇到什么样的阻碍呢?我们下文待续。
更多相关文章
- C语言函数以及函数的使用
- 选项卡使用方法二(Android学习随笔十三)
- 使用AndroidStudio编译NDK的方法及错误解决方式
- Android Studio 配置快捷方式生成JNI头文件的方法
- android 读取DDMS里的文件时打不开,解决方法
- Android:Manifest merger failed with multiple errors, see log
- android中真正destroy掉activity的方法
- Android旋转屏幕不销毁数据的方法
- Android程序设置成横屏方法