主要参考自:React Native通讯原理:http://www.jianshu.com/p/17d6f6c57a5c
1.通讯框架图
2.Native调用JS
Native调用JS流程分析:
- MessageQueue把Native调用的方法放到JavaScriptCore中
- JS Module把可以调用的方法放到MessageQueue的一个对列中
- Native从JavaScriptCore中拿到JS的调用入口,并把Module Name、Method Name、Parameters传过去
- 执行JS Module的方法
个人结合源码分析理解:
CatalystInstanceImpl包含了JavaScriptModuleRegistry,后者包含了JS模块在JAVA中对应的接口,例如index.android.js中有这么一段
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
在 CatalystInstanceImpl实例化的时候, JavaScriptModuleRegistry中就已经被放入了相关接口的class原型(点击我看看如何被存放的)AppRegistry这个模块在JAVA中有对应的JAVA接口
package com.facebook.react.uimanager; import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.WritableMap; /** * JS module interface - main entry point for launching React application for a given key. */ public interface AppRegistry extends JavaScriptModule { void runApplication(String appKey, WritableMap appParameters); void unmountApplicationComponentAtRootTag(int rootNodeTag); void startHeadlessTask(int taskId, String taskKey, WritableMap data); }
那么getJSModule是干什么的呢,其实他是生成JS在JAVA中的接口的动态代理,我们知道,动态代理是实现了接口的方法的,而在每个方法其实是调用
JavaScriptModuleInvocationHandler中的invoke方式,传入接口的方法名和参数,之所以通过动态代理,我们的目的就是把接口的方式和参数传到JS那边,另外这个动态代理
也以便于JAVA端对象。从这里我们可以看到Cataly的含义是催化剂,催化什么呢,现在看来,就是催化我们的JS中JAVA的接口转化为实例。
JAVAScriptModuleInvocationHandler有一个Cataly实例,invoke其实是调用了Cataly实例的callFunction,而callFunction里面是一个native方法
private native void callJSCallback(ExecutorToken executorToken, int callbackID, NativeArray arguments);
现在于是我们就把JS在JAVA端的接口中的方法名字和参数传递给了C++端处理了。
现在再看看CatalyInstance这个,他实际上桥接了我们的C++端和JAVA端,催化了JS在JAVA端的接口产生实例(动态代理),是通信的一个关键类
现在我们通过JNI来到了libreactnativejnifb.so里面,他里面有个方法叫callJSCallback
在上面加载bundle文件的时候,会执行下面C端或者C++端的JSCExecutor的方法
(
JSCEXEcutor:我理解是JS在C端的执行者
1.负责把JS函数映射成C对象
2.通过JSCORE中的
JSObjectCallAsFunction方法,传入映射的C对象,和JAVA或OC的调用信息,以JS Function的形式执行,走到JS端
),把JS函数以C对象的形式存储下来,JNI实际执行的是到C实例
void JSCExecutor::bindBridge() throw(JSException) {
auto global = Object::getGlobalObject(m_context);
auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
if (batchedBridgeValue.isUndefined()) {
throwJSExecutionException("Could not get BatchedBridge, make sure your bundle is packaged correctly");
}
auto batchedBridge = batchedBridgeValue.asObject(); m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue"). asObject();
m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty( "invokeCallbackAndReturnFlushedQueue").asObject();
m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
}
把三个JS函数当成C对象存储下来,JNI调用到这几个C对象
JNI执行时候 通过JSCExcutor执行 jscore中的
JSObjectCallAsFunction 方法,传入一个JS映射的C对象,和相关参数,从而开始JS代码的执行
JSValueRef result = JSObjectCallAsFunction(m_context, m_obj, thisObj, nArgs, args, &exn)
JS端被映射的相关函数如下
在JS BUNDEL生成的时会在JS全局变量里产生一个MESSAGEQUEUE,
const BatchedBridge = new MessageQueue(
() => global.__fbBatchedBridgeConfig,
serializeNativeParams
);
MESSAGEQUEUE里面有三个方法会在加载JS的时候映射为三个C++对象存下来,其中一个就是
callFunctionReturnFlushedQueue,我们通过JavaScriptCore结合这个callFunctionReturnFlushedQueue在C++中的对象调用到JS,
于是我们来到了JS端,例如(AppRegistry只是一个例子,实际还有很多模块)在
AppRegistry.js里面,
BatchedBridge.registerCallableModule(
'AppRegistry',
AppRegistry
);
通过这样,把本模块注入到MessageQUUE中的一个MAP对象中,而MessageQueue中的方式callFunctionReturnFlushedQueue中接收的参数执行callback,而找到相应的模块中的函数调用JS的APPly方式执行这个函数
__callFunction(module: string, method: string, args: any) {
...
const moduleMethods = this._callableModules[module];
...
const result = moduleMethods[method].apply(moduleMethods, args);
Systrace.endEvent();
return result;
}
案例:
下面这个
AppRegistry javascript module 被java 调用的例子