关于做者javascript
郭孝星,程序员,吉他手,主要从事Android平台基础架构方面的工做,欢迎交流技术方面的问题,能够去个人Github提issue或者发邮件至guoxiaoxingse@163.com与我交流。前端
文章目录java
从2016年中开始,我司开始筹措推动React Native在全公司的推广使用,从最基础的基础框架搭建开始,到各类组件库、开发工具的完善,经历了诸多波折,也累积了不少经验。今年的工做也 立刻接近尾声,打算写几篇文章来对这一年多的实践经验作个总结。读者有什么问题或者想要交流的地方,能够去vinci提issue。node
预先善其事,必先利其器。开篇第一篇文章咱们仍是从React Native实现原理讲起,事实上原理分析的文章以前就有写过,可是鉴于最新的版本0.52.0源码有 很多的改动,咱们就再从新温习一下,这样过渡到后续的内容,才更加容易理解。react
源码地址:https://github.com/facebook/react-nativec++
当你拿到React Native的源码的时候,它的目录结构是这样的:程序员
整体来看,整套React Native框架分为三层,以下图所示:github
注:JSCore,即JavaScriptCore,JS解析的核心部分,IOS使用的是内置的JavaScriptCore,Androis上使用的是 https://webkit.org 家的jsc.so。web
经过上面的分析,咱们理解了React Native的框架结构,除此以外,咱们还要理解整套框架里的一些重要角色,以下所示:
以上即是整套框架中关键的角色,值得一提的是,当页面真正渲染出来之后,它实际上仍是Native代码,React Native的做用就是把JavaScript代码映射成Native代码以及实现两端 的通讯,因此咱们在React Native基础框架搭建的过程当中,指导思路之一就是弱化Native与RN的边界与区别,让业务开发组感觉不到二者的区别,从而简化开发流程。
好,有了对React Native框架的总体理解,咱们来继续分析一个RN页面是如何启动并渲染出来的,这也是咱们关心的主要问题。后续的基础框架的搭建、JS Bundle分包加载、渲染性能优化 等都会围绕着着一块作文章。
咱们知道RN的页面也是依托Activity,React Native框架里有一个ReactActivity,它就是咱们RN页面的容器。ReactActivity里有个ReactRootView,正如它的名字那样,它就是 ReactActivity的root View,最终渲染出来的view都会添加到这个ReactRootView上。ReactRootView调用本身的startReactApplication()方法启动了整个RN页面,在启动的过程 中先去建立页面上下文ReactContext,而后再去加载、执行并将JavaScript映射成Native Widget,最终一个RN页面就显示在了用户面前。
整个RN页面的启动流程图以下所示:
这个流程看起来有点长,但实际上重要的东西并很少,咱们当前只须要重点关注四个问题:
咱们先来看第一个问题,咱们都知道要使用RN页面,就须要先初始化一个ReactNativeHost,它是一个抽象类,ReactInstanceManager就是在这个类里被建立的,以下所示:
public abstract class ReactNativeHost {
protected ReactInstanceManager createReactInstanceManager() {
ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
//应用上下文
.setApplication(mApplication)
//JSMainModuleP至关于应用首页的js Bundle,能够传递url从服务器拉取js Bundle
//固然这个只在dev模式下可使用
.setJSMainModulePath(getJSMainModuleName())
//是否开启dev模式
.setUseDeveloperSupport(getUseDeveloperSupport())
//红盒的回调
.setRedBoxHandler(getRedBoxHandler())
//JS执行器
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
//自定义UI实现机制,这个咱们通常用不到
.setUIImplementationProvider(getUIImplementationProvider())
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
//添加咱们外面设置的Package
for (ReactPackage reactPackage : getPackages()) {
builder.addPackage(reactPackage);
}
//获取js Bundle的加载路径
String jsBundleFile = getJSBundleFile();
if (jsBundleFile != null) {
builder.setJSBundleFile(jsBundleFile);
} else {
builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
}
return builder.build();
}
}
复制代码
咱们再来看第二个问题,ReactContext建立流程序列图以下所示:
能够发现,最终建立ReactContext是createReactContext()方法,咱们来看看它的实现。
public class ReactInstanceManager {
private ReactApplicationContext createReactContext( JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()");
ReactMarker.logMarker(CREATE_REACT_CONTEXT_START);
//ReactApplicationContext是ReactContext的包装类。
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
//debug模式里开启异常处理器,就是咱们开发中见到的调试工具(红色错误框等)
if (mUseDeveloperSupport) {
reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
}
//建立JavaModule注册表
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
//建立CatalystInstanceImpl的Builder,它是三端通讯的管理类
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
//JS执行器
.setJSExecutor(jsExecutor)
//Java Module注册表
.setRegistry(nativeModuleRegistry)
//JS Bundle加载器
.setJSBundleLoader(jsBundleLoader)
//Java Exception处理器
.setNativeModuleCallExceptionHandler(exceptionHandler);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);
// CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
final CatalystInstance catalystInstance;
//构建CatalystInstance实例
try {
catalystInstance = catalystInstanceBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
}
if (mBridgeIdleDebugListener != null) {
catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
}
if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");
}
ReactMarker.logMarker(ReactMarkerConstants.PRE_RUN_JS_BUNDLE_START);
//开启加载执行JS Bundle
catalystInstance.runJSBundle();
//关联catalystInstance与reactContext
reactContext.initializeWithInstance(catalystInstance);
return reactContext;
}
}
复制代码
在这个方法里完成了RN页面上下文ReactContext的建立,咱们先来看看这个方法的两个入参:
能够看到在ReactContext建立的过程当中,主要作了如下几件事情:
另外一个重要的角色CatalystInstance出现了,前面咱们也说过它是三端通讯的中枢。关于通讯的具体实现咱们会在接下来的通讯机制小节来说述,咱们先来接着看JS的加载过程。
在分析JS Bundle的加载流程以前,咱们先来看一下上面提到CatalystInstance,它是一个接口,其实现类是CatalystInstanceImpl,咱们来看看它的构造方法。
public class CatalystInstanceImpl implements CatalystInstance {
private CatalystInstanceImpl( final ReactQueueConfigurationSpec reactQueueConfigurationSpec, final JavaScriptExecutor jsExecutor, final NativeModuleRegistry nativeModuleRegistry, final JSBundleLoader jsBundleLoader, NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
mHybridData = initHybrid();
//建立三大线程:UI线程、Native线程与JS线程
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
reactQueueConfigurationSpec,
new NativeExceptionHandler());
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
mNativeModuleRegistry = nativeModuleRegistry;
//建立JS Module注册表实例,这个在之前的代码版本中是在上面的createReactContext()方法中建立的
mJSModuleRegistry = new JavaScriptModuleRegistry();
mJSBundleLoader = jsBundleLoader;
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
mTraceListener = new JSProfilerTraceListener(this);
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge");
//在C++层初始化通讯桥
initializeBridge(
new BridgeCallback(this),
jsExecutor,
mReactQueueConfiguration.getJSQueueThread(),
mNativeModulesQueueThread,
mNativeModuleRegistry.getJavaModules(this),
mNativeModuleRegistry.getCxxModules());
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext());
}
}
复制代码
这个函数的入参大部分咱们都已经很熟悉了,咱们单独说说这个ReactQueueConfigurationSpec,它用来建立ReactQueueConfiguration的实例,ReactQueueConfiguration 一样是个接口,它的实现类是ReactQueueConfigurationImpl。
ReactQueueConfiguration的定义以下:
public interface ReactQueueConfiguration {
//UI线程
MessageQueueThread getUIQueueThread();
//Native线程
MessageQueueThread getNativeModulesQueueThread();
//JS线程
MessageQueueThread getJSQueueThread();
void destroy();
}
复制代码
能够看着这个接口的做用就是建立三个带消息队列的线程:
能够看到CatalystInstance对象在构建的时候,主要作了两件事情:
咱们接着来看JS Bundle的加载流程,JS Bundle的加载其实是指C++层完成的,咱们看一下序列图。
注:JS Bundle有三种加载方式:
从这个序列图上咱们能够看出,真正加载执行JS的地方就是JSCExector.cpp的loadApplicationScript()方法。
void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script, std::string sourceURL) {
SystraceSection s("JSCExecutor::loadApplicationScript", "sourceURL", sourceURL);
...
switch (jsStatus) {
case JSLoadSourceIsCompiled:
if (!bcSourceCode) {
throw std::runtime_error("Unexpected error opening compiled bundle");
}
//调用JavaScriptCore里的方法验证JS是否有效,并解释执行
evaluateSourceCode(m_context, bcSourceCode, jsSourceURL);
flush();
ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
ReactMarker::logTaggedMarker(ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
return;
case JSLoadSourceErrorVersionMismatch:
throw RecoverableError(explainLoadSourceStatus(jsStatus));
case JSLoadSourceErrorOnRead:
case JSLoadSourceIsNotCompiled:
// Not bytecode, fall through.
break;
}
}
...
复制代码
能够看到这个方法主要是调用JavaScriptCore里的evaluateSourceCode()方法验证JS是否有效,并解释执行。而后在调用flush()方法层调用JS层的里 方法执行JS Bundle。
void JSCExecutor::flush() {
SystraceSection s("JSCExecutor::flush");
if (m_flushedQueueJS) {
//调用MessageQueue.js的flushedQueue()方法
callNativeModules(m_flushedQueueJS->callAsFunction({}));
return;
}
// When a native module is called from JS, BatchedBridge.enqueueNativeCall()
// is invoked. For that to work, require('BatchedBridge') has to be called,
// and when that happens, __fbBatchedBridge is set as a side effect.
auto global = Object::getGlobalObject(m_context);
auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
// So here, if __fbBatchedBridge doesn't exist, then we know no native calls
// have happened, and we were able to determine this without forcing
// BatchedBridge to be loaded as a side effect.
if (!batchedBridgeValue.isUndefined()) {
// If calls were made, we bind to the JS bridge methods, and use them to
// get the pending queue of native calls.
bindBridge();
callNativeModules(m_flushedQueueJS->callAsFunction({}));
} else if (m_delegate) {
// If we have a delegate, we need to call it; we pass a null list to
// callNativeModules, since we know there are no native calls, without
// calling into JS again. If no calls were made and there's no delegate,
// nothing happens, which is correct.
callNativeModules(Value::makeNull(m_context));
}
}
复制代码
上面提到flush()方法调用MessageQueue.js的flushedQueue()方法,这是如何作到的呢?🤔。
事实上这是由bindBridge()方法来完成的,bindBridge()从__fbBatchedBridge(__fbBatchedBridge也是被MessageQueue.js设置为全局变量,供C++层读取)对象中取出MessageQueue.js里的四个方法:
并分别存在三个C++变量中:
这样C++就能够调用这四个JS方法。
void JSCExecutor::bindBridge() throw(JSException) {
SystraceSection s("JSCExecutor::bindBridge");
std::call_once(m_bindFlag, [this] {
auto global = Object::getGlobalObject(m_context);
auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
if (batchedBridgeValue.isUndefined()) {
auto requireBatchedBridge = global.getProperty("__fbRequireBatchedBridge");
if (!requireBatchedBridge.isUndefined()) {
batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({});
}
if (batchedBridgeValue.isUndefined()) {
throw JSException("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();
m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnResultAndFlushedQueue").asObject();
});
}
复制代码
至此,JS Bundle已经加载解析完成,进入MessageQueue.js开始执行。
JS Bundle加载完成之后,前面说的createReactContext()就执行完成了,而后开始执行setupReacContext()方法,绑定ReactContext与ReactRootView。 咱们来看一下它的实现。
public class ReactInstanceManager {
private void setupReactContext(final ReactApplicationContext reactContext) {
//...
//执行Java Module的初始化
catalystInstance.initialize();
//通知ReactContext已经被建立爱女
mDevSupportManager.onNewReactContextCreated(reactContext);
//内存状态回调设置
mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);
//复位生命周期
moveReactContextToCurrentLifecycleState();
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START);
synchronized (mAttachedRootViews) {
//将全部的ReactRootView与catalystInstance进行绑定
for (ReactRootView rootView : mAttachedRootViews) {
attachRootViewToInstance(rootView, catalystInstance);
}
}
//...
}
private void attachRootViewToInstance( final ReactRootView rootView, CatalystInstance catalystInstance) {
//...
UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
//将ReactRootView做为根布局
final int rootTag = uiManagerModule.addRootView(rootView);
rootView.setRootViewTag(rootTag);
//执行JS的入口bundle页面
rootView.invokeJSEntryPoint();
//...
}
x
}
复制代码
setupReactContext()方法主要完成每一个ReactRootView与catalystInstance的绑定,绑定的过程主要作两件事情:
JS的页面入口咱们能够设置mJSEntryPoint来自定义入口,若是不设置则是默认的入口AppRegistry。
private void defaultJSEntryPoint() {
//...
try {
//...
String jsAppModuleName = getJSModuleName();
catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
复制代码
这里的调用方式实际上就是原生调用JS的方法,它调用的正是咱们很熟悉的AppRegistry.js,AppRegistry.js调用runApplication()开始执行JS页面的渲染,最终转换为 Native UI显示在手机上。
到此为止,整个RN页面的启动流程就分析完了,咱们接着来看看RN页面是如何渲染最终显示在手机上的。
上面咱们也说了,RN页面的入口通常是AppRegistry.js,咱们就从这个页面入手开始分析RN页面的渲染流程。先看一下RN页面的渲染流程序列图,以下所示:
这个流程比较长,其实主要是方法的调用链多,原理仍是很简单的,咱们先归纳性的总结一下:
如上图所示AppRegistry.registerComponent用来注册组件,在该方法内它会调用AppRegistry.runApplication()来启动js的渲染流程。AppRegistry.runApplication() 会将传入的Component转换成ReactElement,并在外面包裹一层AppContaniner,AppContaniner主要用来提供一些debug工具(例如:红盒)。
以下所示:
function renderApplication<Props: Object>( RootComponent: ReactClass<Props>, initialProps: Props, rootTag: any ) {
invariant(
rootTag,
'Expect to have a valid rootTag, instead got ', rootTag
);
ReactNative.render(
<AppContainer rootTag={rootTag}> <RootComponent {...initialProps} rootTag={rootTag} /> </AppContainer>, rootTag ); } 复制代码
咱们抛开函数调用链,分析其中关键的部分,其余部分都是简单的函数调用。
/** * @param {ReactComponent} instance Instance to render. * @param {containerTag} containerView Handle to native view tag */
renderComponent: function( nextElement: ReactElement<*>, containerTag: number, callback?: ?(() => void) ): ?ReactComponent<any, any, any> {
//将RectElement使用相同的TopLevelWrapper进行包裹
var nextWrappedElement = React.createElement(
TopLevelWrapper,
{ child: nextElement }
);
var topRootNodeID = containerTag;
var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID];
if (prevComponent) {
var prevWrappedElement = prevComponent._currentElement;
var prevElement = prevWrappedElement.props.child;
if (shouldUpdateReactComponent(prevElement, nextElement)) {
ReactUpdateQueue.enqueueElementInternal(prevComponent, nextWrappedElement, emptyObject);
if (callback) {
ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
}
return prevComponent;
} else {
ReactNativeMount.unmountComponentAtNode(containerTag);
}
}
if (!ReactNativeTagHandles.reactTagIsNativeTopRootID(containerTag)) {
console.error('You cannot render into anything but a top root');
return null;
}
ReactNativeTagHandles.assertRootTag(containerTag);
//检查以前的节点是否已经mount到目标节点上,若是有则进行比较处理
var instance = instantiateReactComponent(nextWrappedElement, false);
ReactNativeMount._instancesByContainerID[containerTag] = instance;
// The initial render is synchronous but any updates that happen during
// rendering, in componentWillMount or componentDidMount, will be batched
// according to the current batching strategy.
//将mount任务提交给回调Queue,最终会调用ReactReconciler.mountComponent()
ReactUpdates.batchedUpdates(
batchedMountComponentIntoNode,
instance,
containerTag
);
var component = instance.getPublicInstance();
if (callback) {
callback.call(component);
}
return component;
},
复制代码
该方法主要作了如下事情:
在分析这个函数以前,咱们先来补充一下React组件相关知识。React组件能够分为两种:
instantiateReactComponent(node, shouldHaveDebugID)方法根据对象的type生成元组件或者复合组件。
/** * Given a ReactNode, create an instance that will actually be mounted. * * @param {ReactNode} node * @param {boolean} shouldHaveDebugID * @return {object} A new instance of the element's constructor. * @protected */
function instantiateReactComponent(node, shouldHaveDebugID) {
var instance;
if (node === null || node === false) {
instance = ReactEmptyComponent.create(instantiateReactComponent);
} else if (typeof node === 'object') {
var element = node;
var type = element.type;
if (typeof type !== 'function' && typeof type !== 'string') {
var info = '';
if (process.env.NODE_ENV !== 'production') {
if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {
info += ' You likely forgot to export your component from the file ' + 'it\'s defined in.';
}
}
info += getDeclarationErrorAddendum(element._owner);
!false ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s', type == null ? type : typeof type, info) : _prodInvariant('130', type == null ? type : typeof type, info) : void 0;
}
//若是对象的type为string,则调用ReactHostComponent.createInternalComponent(element)来注入生成组件的逻辑
if (typeof element.type === 'string') {
instance = ReactHostComponent.createInternalComponent(element);
}
//若是是内部元组件,则建立一个type实例
else if (isInternalComponentType(element.type)) {
// This is temporarily available for custom components that are not string
// representations. I.e. ART. Once those are updated to use the string
// representation, we can drop this code path.
instance = new element.type(element);
// We renamed this. Allow the old name for compat. :(
if (!instance.getHostNode) {
instance.getHostNode = instance.getNativeNode;
}
}
//不然,则是用户建立的复合组件,这个时候建立一个ReactCompositeComponentWrapper实例,该实例用来描述复合组件
else {
instance = new ReactCompositeComponentWrapper(element);
}
//当对象为string或者number时,调用ReactHostComponent.createInstanceForText(node)来注入组件生成逻辑。
} else if (typeof node === 'string' || typeof node === 'number') {
instance = ReactHostComponent.createInstanceForText(node);
} else {
!false ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Encountered invalid React node of type %s', typeof node) : _prodInvariant('131', typeof node) : void 0;
}
if (process.env.NODE_ENV !== 'production') {
process.env.NODE_ENV !== 'production' ? warning(typeof instance.mountComponent === 'function' && typeof instance.receiveComponent === 'function' && typeof instance.getHostNode === 'function' && typeof instance.unmountComponent === 'function', 'Only React Components can be mounted.') : void 0;
}
// These two fields are used by the DOM and ART diffing algorithms
// respectively. Instead of using expandos on components, we should be
// storing the state needed by the diffing algorithms elsewhere.
instance._mountIndex = 0;
instance._mountImage = null;
if (process.env.NODE_ENV !== 'production') {
instance._debugID = shouldHaveDebugID ? getNextDebugID() : 0;
}
// Internal instances should fully constructed at this point, so they should
// not get any new fields added to them at this point.
if (process.env.NODE_ENV !== 'production') {
if (Object.preventExtensions) {
Object.preventExtensions(instance);
}
}
return instance;
}
复制代码
该方法根据对象的type生成元组件或者复合组件,具体流程以下:
咱们经过前面的分析,了解了整个UI开始渲染的时机,以及js层的整个渲染流程,接下来,咱们开始分析每一个js的组件时怎么转换成Android的组件,最终显示在屏幕上的。
上面咱们提到元组件与复合组件,事实上复合组件也是递归遍历其中的元组件,而后进行渲染。因此咱们重点关注元组件的生成逻辑。
咱们能够看到,UI渲染主要经过UIManager来完成,UIManager是一个ReactModule,UIManager.js里的操做都会对应到UIManagerModule里来。咱们接着来看看Java层的 渲染流程。
从上图咱们能够很容易看出,Java层的组件渲染分为如下几步:
Java层与JavaScript层的相互调用都不是直接完成的,而是间接经过C++层来完成的。在介绍通讯机制以前咱们先来理解一些基本的概念。
JavaScript Module注册表
提及JavaScript Module注册表,咱们须要先理解3个类/接口:JavaScriptModule、JavaScriptModuleRegistration、JavaScriptModuleRegistry。
Java Module注册表
要理解Java Module注册表,咱们一样也须要理解3个类/接口:NativeModule、ModuleHolder、NativeModuleRegistry。
关于NativeModuleRegistry和JavaScriptModuleRegistry的建立,咱们前面都已经提到管,你们还都记得吗。
这些都是在CatalystInstanceImpl的构建方法里经过native方法initializeBridge()传入了C++层,以下所示:
CatalystInstanceImpl.cpp
void CatalystInstanceImpl::initializeBridge(
jni::alias_ref<ReactCallback::javaobject> callback,
// This executor is actually a factory holder.
JavaScriptExecutorHolder* jseh,
jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,
jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
instance_->initializeBridge(folly::make_unique<JInstanceCallback>(callback),
jseh->getExecutorFactory(),
folly::make_unique<JMessageQueueThread>(jsQueue),
folly::make_unique<JMessageQueueThread>(moduleQueue),
buildModuleRegistry(std::weak_ptr<Instance>(instance_),
javaModules, cxxModules));
}
复制代码
这个方法的参数含义以下所示:
咱们注意这些传入了两个集合:
这两个集合在CatalystInstanceImpl::initializeBridge()被打包成ModuleRegistry传入Instance.cpp.、,以下所示:
**ModuleRegistryBuilder.cpp**
```java
std::unique_ptr<ModuleRegistry> buildModuleRegistry(
std::weak_ptr<Instance> winstance,
jni::alias_ref<jni::JCollection<JavaModuleWrapper::javaobject>::javaobject> javaModules,
jni::alias_ref<jni::JCollection<ModuleHolder::javaobject>::javaobject> cxxModules) {
std::vector<std::unique_ptr<NativeModule>> modules;
for (const auto& jm : *javaModules) {
modules.emplace_back(folly::make_unique<JavaNativeModule>(winstance, jm));
}
for (const auto& cm : *cxxModules) {
modules.emplace_back(
folly::make_unique<CxxNativeModule>(winstance, cm->getName(), cm->getProvider()));
}
if (modules.empty()) {
return nullptr;
} else {
return folly::make_unique<ModuleRegistry>(std::move(modules));
}
}
复制代码
打包好的ModuleRegistry经过Instance::initializeBridge()传入到NativeToJsBridge.cpp中,并在NativeToJsBridge的构造方法中传给JsToNativeBridge,之后JS若是调用Java就能够经过 ModuleRegistry来进行调用。
这里的NativeToJsBridge.cpp与JsToNativeBridge.cpp就是Java与JS相互调用的通讯桥,咱们来看看它们的通讯方式。
关于整个RN的通讯机制,能够用一句话来归纳:
JNI做为C++与Java的桥梁,JSC做为C++与JavaScript的桥梁,而C++最终链接了Java与JavaScript。
RN应用通讯桥结构图以下所示:
理解了整个通讯桥的结构,Java与JS是如何互相掉用的就很清晰了。
注:若是想要了解关于通讯机制的更多细节,能够去看个人这篇文章6ReactNative源码篇:通讯机制。