native react 底层实现_React Native之底层源码分析篇

本文深入探讨React Native的底层通信机制,包括Java层、C++层和JS层的三层结构,以及它们如何通过Bridge进行通信。文章通过源码分析,解释了模块配置表在通信过程中的作用,详细描述了从创建ReactInstanceManager到调用Java模块的过程,并展示了关键类如ReactInstanceManager、ReactRootView、CatalystInstance和NativeModuleRegistry的工作原理。最后,总结了Java调用JS和JS调用Java的流程,帮助读者理解RN框架的核心工作方式。
摘要由CSDN通过智能技术生成

学习React-Native有一段时间了。今天就从源码的角度来分析下React-Native底层的通信机制。了解下底层是如何通信的对开发也有所好处。

概要

先大概讲一下React-Native的通信过程。RN主要的通信在于java与js之间,平常我们写的jsx代码最终会调用到原生的View。上一篇博客我们也了解到了要新建一个原生模块需要在java层和js层分别写一个Module,那这彼此之间联系是如何实现的呢?

层次结构

RN总共分为三层,java层,C++层,js层。借用一幅图来看下:

Java层:java层就是app原生代码,它通过启动C++层的javascript解析器javascriptCore来执行js代码,从而构建原生UI等。java层依赖于众多优秀开源库,在图片处理使用的是Fresco,网络通信使用的是okhttp,Json解析工具用jackson,动画库用NineOldAndroids等,在java层原生的功能均封装为Module,如Toast和Log等。

C++层:c++层最主要是封装了JavaScriptCore,它是一个全新的支持ES6的webKit。Bridge连接了java与js之间的通信。解析js文件是通过JSCExectutor进行的。

Js层:主要处理事件分发及UI Layout,平常开发最常用的。通用jsx来写业务代码,通过flexbox来实现布局。不依赖DOM。由于react有 DOM diff这个算法,所以它的效率非常高。

通信机制

在Java层与Js层的bridge分别存有相同一份模块配置表,Java与Js互相通信时,通过将里配置表中的moduleID,methodID转换成json数据的形式传递给到C++层,C++层传送到js层,通过js层的的模块配置表找到对应的方法进行执行,如果有callback,则回传给java层。这里只是大概介绍,后面会有详细讲解。

主要流程与主要类

先看下java层的流程图:

ReactInstanceManager:主要是用来创建及管理CatalyInstance的实例的上层接口,控制开发调试,生命周期与ReactRootView所在activity保持一致。 ReactRootView:为启动入口核心类,负责监听及分发事件并重新渲染元素,App启动后,其将作为App的root view。 CatalystInstance:提供Java与Js互通的环境,创建Java模块注册表及Javascript模块注册表,并遍历实例化模块,最后通过ReactBridge将Js Bundle传送到Js引擎。 JSBuilderLoader:缓存了JsBundle的信息,封装了上层加载JsBundle相关接口,CatalystInstance通过其间接调用ReactBridge去加载文件。 NativeModuleRegistry:Java层模块注册表,即暴露给Js的API集合。 JavascriptModuleRegistry:Js层模块注册表,负责将所有JavaScriptModule注册到CatalystInstance。 CoreModulePackage:CoreModulesPackage里面定义了RN框架核心的一些Java和JS的module,创建NativeModules&JsModules组件模块。

源码分析

加载Module

首先看MainActivity的

protected ListgetPackages() {

return Arrays.asList(

new MainReactPackage(),

new AppReactPackage()

);

}

AppReactPackage是我们自定义的一个ReactPackage,也就是说如果自己定义了新组件,要在这里添加。看下ReactActivity,看它的onCreate方法:

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

if(this.getUseDeveloperSupport() && VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(this)) {

Intent mReactRootView = new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION");

this.startActivity(mReactRootView);

FLog.w("React", "Overlay permissions needs to be granted in order for react native apps to run in dev mode");

Toast.makeText(this, "Overlay permissions needs to be granted in order for react native apps to run in dev mode", 1).show();

}

this.mReactInstanceManager = this.createReactInstanceManager();

ReactRootView mReactRootView1 = this.createRootView();

mReactRootView1.startReactApplication(this.mReactInstanceManager, this.getMainComponentName(), this.getLaunchOptions());

this.setContentView(mReactRootView1);

}

主要完成三个功能,通过createReactInstanceManager创建ReactInstanceManager,它主要是用来创建及管理CatalyInstance的实例的上层接口。第二步是通过createRootView来创建ReactRootView。最后调用ReactRootView的startReactApplication来启动应用,并把它当作rootview setContentView到界面上。重点看startReactApplication方法:

public void startReactApplication(ReactInstanceManager reactInstanceManager, String moduleName, @Nullable Bundle launchOptions) {

UiThreadUtil.assertOnUiThread();

Assertions.assertCondition(this.mReactInstanceManager == null, "This root view has already been attached to a catalyst instance manager");

this.mReactInstanceManager = reactInstanceManager;

this.mJSModuleName = moduleName;

this.mLaunchOptions = launchOptions;

if(!this.mReactInstanceManager.hasStartedCreatingInitialContext()) {

this.mReactInstanceManager.createReactContextInBackground();

}

if(this.mWasMeasured && this.mIsAttachedToWindow) {

this.mReactInstanceManager.attachMeasuredRootView(this);

this.mIsAttachedToInstance = true;

this.getViewTreeObserver().addOnGlobalLayoutListener(this.getKeyboardListener());

} else {

this.mAttachScheduled = true;

}

}

mJSModuleName是与前端约定好所要启动的JS Application Name。先看createReactContextInBackground方法,它位于ReactInstanceManager的实现类ReactInstanceManagerImpl中:

public void recreateReactContextInBackground() {

Assertions.assertCondition(this .mHasStartedCreatingInitialContext , "recreateReactContextInBackground should only be called after the initial createReactContextInBackground call.") ;

this. recreateReactContextInBackgroundInner() ;

}

createReactContextInBackground最终调用到recreateReactContextInBackgroundInner:

private void recreateReactContextInBackgroundInner() {

UiThreadUtil.assertOnUiThread();

if( this.mUseDeveloperSupport && this.mJSMainModuleName != null) {

if (this.mDevSupportManager.hasUpToDateJSBundleInCache()) {

this .onJSBundleLoadedFromServer() ;

} else if(this .mJSBundleFile == null) {

this .mDevSupportManager.handleReloadJS() ;

} else {

this .mDevSupportManager.isPackagerRunning( new PackagerStatusCallback() {

public void onPackagerStatusFetched( final boolean packagerIsRunning) {

UiThreadUtil.runOnUiThread( new Runnable() {

public void run() {

if(packagerIsRunning) {

ReactInstanceManagerImpl.this .mDevSupportManager.handleReloadJS() ;

} else {

ReactInstanceManagerImpl.this .recreateReactContextInBackgroundFromBundleFile() ;

}

}

}) ;

}

});

}

} else {

this .recreateReactContextInBackgroundFromBundleFile() ;

}

}

接着调用recreateReactContextInBackgroundFromBundleFile:

private void recreateReactContextInBackgroundFromBundleFile() {

this.recreateReactContextInBackground(new com.facebook.react.bridge.JSCJavaScriptExecutor.Factory(), JSBundleLoader.createFileLoader(this.mApplicationContext, this.mJSBundleFile));

}

经过一系列的周转,最后调用到了recreateReactContextInBackground:

private void recreateReactContextInBackground(com.facebook.react.bridge.JavaScriptExecutor.Factory jsExecutorFactory, JSBundleLoader jsBundleLoader) {

UiThreadUtil.assertOnUiThread();

ReactInstanceManagerImpl.ReactContextInitParams initParams = new ReactInstanceManagerImpl.ReactContextInitParams(jsExecutorFactory , jsBundleLoader);

if( this.mReactContextInitAsyncTask == null) {

this .mReactContextInitAsyncTask = new ReactInstanceManagerImpl.ReactContextInitAsyncTask( null);

this.mReactContextInitAsyncTask.execute( new ReactInstanceManagerImpl.ReactContextInitParams[]{initParams}) ;

} else {

this .mPendingReactContextInitParams = initParams ;

}

}

上面代码通过ReactContextInitAsyncTask这个AsyncTask来初始化ReactCotext。

private final class ReactContextInitAsyncTask extends AsyncTask> {

private ReactContextInitAsyncTask() {

}

protected void onPreExecute() {

if(ReactInstanceManagerImpl.this.mCurrentReactContext != null) {

ReactInstanceManagerImpl.this.tearDownReactContext(ReactInstanceManagerImpl.this.mCurrentReactContext);

ReactInstanceManagerImpl.this.mCurrentReactContext = null;

}

}

protected ReactInstanceManagerImpl.ResultdoInBackground(ReactInstanceManagerImpl.ReactContextInitParams... params) {

Assertions.assertCondition(params != null && params.length > 0 && params[0] != null);

try {

JavaScriptExecutor e = params[0].getJsExecutorFactory().create(ReactInstanceManagerImpl.this.mJSCConfig == null?new WritableNativeMap():ReactInstanceManagerImpl.this.mJSCConfig.getConfigMap());

return ReactInstanceManagerImpl.Result.of((Object)ReactInstanceManagerImpl.this.createReactContext(e, params[0].getJsBundleLoader()));

} catch (Exception var3) {

return ReactInstanceManagerImpl.Result.of(var3);

}

}

protected void onPostExecute(ReactInstanceManagerImpl.Resultresult) {

try {

ReactInstanceManagerImpl.this.setupReactContext((ReactApplicationContext)result.get());

} catch (Exception var6) {

ReactInstanceManagerImpl.this.mDevSupportManager.handleException(var6);

} finally {

ReactInstanceManagerImpl.this.mReactContextInitAsyncTask = null;

}

if(ReactInstanceManagerImpl.this.mPendingReactContextInitParams != null) {

ReactInstanceManagerImpl.this.recreateReactContextInBackground(ReactInstanceManagerImpl.this.mPendingReactContextInitParams.getJsExecutorFactory(), ReactInstanceManagerImpl.this.mPendingReactContextInitParams.getJsBundleLoader());

ReactInstanceManagerImpl.this.mPendingReactContextInitParams = null;

}

}.reactcontextinitparams,>

ReactContextInitAsyncTask为创建ReactContext的核心类,随后,调用createReactContext进一步创建ReactContext。在创建完React Context后会调用setUpReactContext,将ReactRootView做为Root View传递给UIManagerModule,调用AppRegistry的runApplication去启动Js Application等。看createReactContext的代码:

private ReactApplicationContext createReactContext(JavaScriptExecutor jsExecutor , JSBundleLoader jsBundleLoader) {

FLog.i("React" , "Creating react context.");

ReactMarker.logMarker( "CREATE_REACT_CONTEXT_START" );

this.mSourceUrl = jsBundleLoader.getSourceUrl() ;

Builder nativeRegistryBuilder = new Builder();

com.facebook.react.bridge.JavaScriptModulesConfig.Builder jsModulesBuilder = new com.facebook.react.bridge.JavaScriptModulesConfig.Builder() ;

ReactApplicationContext reactContext = new ReactApplicationContext( this.mApplicationContext);

if( this.mUseDeveloperSupport) {

reactContext.setNativeModuleCallExceptionHandler(this.mDevSupportManager) ;

}

ReactMarker.logMarker("PROCESS_PACKAGES_START" );

Systrace.beginSection( 0L, "createAndProcessCoreModulesPackage" );

try {

CoreModulesPackage nativeModuleRegistry = new CoreModulesPackage( this, this.mBackBtnHandler , this.mUIImplementationProvider);

this.processPackage(nativeModuleRegistry , reactContext, nativeRegistryBuilder, jsModulesBuilder) ;

} finally {

Systrace.endSection(0L );

}

Iterator nativeModuleRegistry2 = this .mPackages.iterator();

while(nativeModuleRegistry2.hasNext()) {

ReactPackage javaScriptModulesConfig = (ReactPackage)nativeModuleRegistry2.next();

Systrace.beginSection( 0L, "createAndProcessCustomReactPackage" );

try {

this .processPackage(javaScriptModulesConfig , reactContext, nativeRegistryBuilder, jsModulesBuilder) ;

} finally {

Systrace.endSection(0L) ;

}

}

ReactMarker.logMarker("PROCESS_PACKAGES_END" );

ReactMarker.logMarker( "BUILD_NATIVE_MODULE_REGISTRY_START" );

Systrace.beginSection( 0L, "buildNativeModuleRegistry" );

NativeModuleRegistry nativeModuleRegistry1 ;

try {

nativeModuleRegistry1 = nativeRegistryBuilder.build();

} finally {

Systrace.endSection(0L );

ReactMarker.logMarker( "BUILD_NATIVE_MODULE_REGISTRY_END" );

}

ReactMarker.logMarker("BUILD_JS_MODULE_CONFIG_START" );

Systrace.beginSection( 0L, "buildJSModuleConfig" );

JavaScriptModulesConfig javaScriptModulesConfig1 ;

try {

javaScriptModulesConfig1 = jsModulesBuilder.build();

} finally {

Systrace.endSection(0L );

ReactMarker.logMarker( "BUILD_JS_MODULE_CONFIG_END" );

}

Object exceptionHandler = this .mNativeModuleCallExceptionHandler != null?this .mNativeModuleCallExceptionHandler: this.mDevSupportManager;

com.facebook.react.bridge.CatalystInstanceImpl.Builder catalystInstanceBuilder = ( new com.facebook.react.bridge.CatalystInstanceImpl.Builder()).setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()).setJSExecutor(jsExecutor).setRegistry(nativeModuleRegistry1).setJSModulesConfig(javaScriptModulesConfig1).setJSBundleLoader(jsBundleLoader).setNativeModuleCallExceptionHandler((NativeModuleCallExceptionHandler)exceptionHandler) ;

ReactMarker.logMarker( "CREATE_CATALYST_INSTANCE_START" );

Systrace.beginSection( 0L, "createCatalystInstance" );

CatalystInstanceImpl catalystInstance ;

try {

catalystInstance = catalystInstanceBuilder.build();

} finally {

Systrace.endSection(0L );

ReactMarker.logMarker( "CREATE_CATALYST_INSTANCE_END" );

}

if (this.mBridgeIdleDebugListener != null) {

catalystInstance.addBridgeIdleDebugListener(this.mBridgeIdleDebugListener) ;

}

reactContext.initializeWithInstance(catalystInstance);

ReactMarker.logMarker( "RUN_JS_BUNDLE_START" );

Systrace.beginSection( 0L, "runJSBundle" );

try {

catalystInstance.runJSBundle();

} finally {

Systrace.endSection(0L );

ReactMarker.logMarker( "RUN_JS_BUNDLE_END" );

}

return reactContext;

}

代码很长,我们来分段分析。

第一步

com.facebook.react.bridge.JavaScriptModulesConfig.Builder jsModulesBuilder = new com.facebook.react.bridge.JavaScriptModulesConfig.Builder();

创建JavaScriptModulesConfig。

第二步

ReactApplicationContext reactContext = new ReactApplicationContext(this.mApplicationContext);

创建ReactApplicationContext上下文。

第三步

try {

CoreModulesPackage nativeModuleRegistry = new CoreModulesPackage(this, this.mBackBtnHandler, this.mUIImplementationProvider);

this.processPackage(nativeModuleRegistry, reactContext, nativeRegistryBuilder, jsModulesBuilder);

} finally {

Systrace.endSection(0L);

}

Iterator nativeModuleRegistry2 = this.mPackages.iterator();

while(nativeModuleRegistry2.hasNext()) {

ReactPackage javaScriptModulesConfig = (ReactPackage)nativeModuleRegistry2.next();

Systrace.beginSection(0L, "createAndProcessCustomReactPackage");

try {

this.processPackage(javaScriptModulesConfig, reactContext, nativeRegistryBuilder, jsModulesBuilder);

} finally {

Systrace.endSection(0L);

}

}

创建ReactPackage。ReactPackage主要通过createNativeModules、createJSModules和createViewManagers等API去创建本地模块,JS模块及视图组件等。ReactPackage分为framework的CoreModulesPackage和业务方可选的基础MainReactPackage,CoreModulesPackage封装了大部分通信,调试核心类,如UIManagerModule,这个负责控制Js层Dom到Native View的核心类;看下processPackage方法:

private void processPackage(ReactPackage reactPackage, ReactApplicationContext reactContext, Builder nativeRegistryBuilder, com.facebook.react.bridge.JavaScriptModulesConfig.Builder jsModulesBuilder) {

Iterator i$ = reactPackage.createNativeModules(reactContext).iterator();

while(i$.hasNext()) {

NativeModule jsModuleClass = (NativeModule)i$.next();

nativeRegistryBuilder.add(jsModuleClass);

}

i$ = reactPackage.createJSModules().iterator();

while(i$.hasNext()) {

Class jsModuleClass1 = (Class)i$.next();

jsModulesBuilder.add(jsModuleClass1);

}

}

很简单,拿到具体的native和JS的module把它们添加到对应的builder中。先是添加CoreModulesPackage中的module再添加我们自定义的module,先看CoreModulesPackage中的createNativeModules方法:

public ListcreateNativeModules(ReactApplicationContext catalystApplicationContext) {

Systrace.beginSection(0L, "createUIManagerModule");

UIManagerModule uiManagerModule;

try {

List viewManagersList = this.mReactInstanceManager.createAllViewManagers(catalystApplicationContext);

uiManagerModule = new UIManagerModule(catalystApplicationContext, viewManagersList, this.mUIImplementationProvider.createUIImplementation(catalystApplicationContext, viewManagersList));

} finally {

Systrace.endSection(0L);

}

return Arrays.asList(new NativeModule[]{new AnimationsDebugModule(catalystApplicationContext, this.mReactInstanceManager.getDevSupportManager().getDevSettings()), new AndroidInfoModule(), new DeviceEventManagerModule(catalystApplicationContext, this.mHardwareBackBtnHandler), new ExceptionsManagerModule(this.mReactInstanceManager.getDevSupportManager()), new Timing(catalystApplicationContext), new SourceCodeModule(this.mReactInstanceManager.getSourceUrl(), this.mReactInstanceManager.getDevSupportManager().getSourceMapUrl()), uiManagerModule, new DebugComponentOwnershipModule(catalystApplicationContext)});

}

就是将UIManagerModule、AnimationsDebugModule等装到build中。

接着添加我们自定义的组件,以自定义Log为例,需要如下内容吗:

public class AppReactPackage implements ReactPackage{

@Override

public ListcreateNativeModules(ReactApplicationContext reactApplicationContext) {

Listmodules=new ArrayList<>();

modules.add(new LogModule(reactApplicationContext));

return modules;

}

@Override

public List> createJSModules() {

return Collections.emptyList();

}

@Override

public ListcreateViewManagers(ReactApplicationContext reactApplicationContext) {

return Collections.emptyList();

}

}>

很简单,装到自定义的List中。

第四步

CatalystInstanceImpl catalystInstance;

try {

catalystInstance = catalystInstanceBuilder.build();

} finally {

Systrace.endSection(0L);

ReactMarker.logMarker("CREATE_CATALYST_INSTANCE_END");

}

创建CatalystInstance。CatalystInstance并不直接面向开发者,开发者通ReactInstanceManger间接操作CatalystInstance。CatalystInstance持有对ReactBridge的引用,主要通过ReactBridge这个JNI类去实现Java层与Js层的通信,ReactBridge由CatalystInstance的Constructor创建。同时初始化的时候调用了ReactQueueConfigurationSpec.createDefault创建了ReactNative通信的两个线程 JsQueueThread&NativeModulesQueueThread;

在这里ReactBridge由CatalystInstance的Constructor创建。看下它的构造函数:

private CatalystInstanceImpl(ReactQueueConfigurationSpec ReactQueueConfigurationSpec, final JavaScriptExecutor jsExecutor, NativeModuleRegistry registry, final JavaScriptModulesConfig jsModulesConfig, JSBundleLoader jsBundleLoader, NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {

this.mPendingJSCalls = new AtomicInteger(0);

this.mJsPendingCallsTitleForTrace = "pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement();

this.mDestroyed = false;

this.mJSToJavaCallsTeardownLock = new Object();

this.mJavaToJSCallsTeardownLock = new Object();

this.mInitialized = false;

FLog.d("React", "Initializing React Bridge.");

this.mReactQueueConfiguration = ReactQueueConfigurationImpl.create(ReactQueueConfigurationSpec, new CatalystInstanceImpl.NativeExceptionHandler(null));

this.mBridgeIdleListeners = new CopyOnWriteArrayList();

this.mJavaRegistry = registry;

this.mJSModuleRegistry = new JavaScriptModuleRegistry(this, jsModulesConfig);

this.mJSBundleLoader = jsBundleLoader;

this.mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;

this.mTraceListener = new CatalystInstanceImpl.JSProfilerTraceListener(null);

try {

this.mBridge = (ReactBridge)this.mReactQueueConfiguration.getJSQueueThread().callOnQueue(new Callable() {

public ReactBridge call() throws Exception {

Systrace.beginSection(0L, "initializeBridge");

ReactBridge var1;

try {

var1 = CatalystInstanceImpl.this.initializeBridge(jsExecutor, jsModulesConfig);

} finally {

Systrace.endSection(0L);

}

return var1;

}

}).get();

} catch (Exception var8) {

throw new RuntimeException("Failed to initialize bridge", var8);

}

}

注意到这行代码:

this.mJSModuleRegistry = new JavaScriptModuleRegistry(this, jsModulesConfig);

这里通过jsModulesConfig(封装了module)创建了JSModuleRegistry。好了js注册表终于创建成功了。这里有两个问题,native注册表在哪创建呢,还有就是注册表什么时候传给js层呢。先留着这两个问题。

接下来看下initializeBridge方法:

private ReactBridge initializeBridge (JavaScriptExecutor jsExecutor, JavaScriptModulesConfig jsModulesConfig) {

this .mReactQueueConfiguration.getJSQueueThread().assertIsOnThread() ;

Assertions.assertCondition( this.mBridge == null, "initializeBridge should be called once" );

Systrace.beginSection( 0L, "ReactBridgeCtor" );

ReactBridge bridge ;

try {

bridge = new ReactBridge(jsExecutor, new CatalystInstanceImpl.NativeModulesReactCallback( null), this.mReactQueueConfiguration.getNativeModulesQueueThread()) ;

this.mMainExecutorToken = bridge.getMainExecutorToken() ;

} finally {

Systrace.endSection(0L );

}

Systrace.beginSection(0L , "setBatchedBridgeConfig");

try {

bridge.setGlobalVariable("__fbBatchedBridgeConfig" , this.buildModulesConfigJSONProperty( this.mJavaRegistry, jsModulesConfig));

bridge.setGlobalVariable( "__RCTProfileIsProfiling" , Systrace.isTracing( 0L)?"true" :"false") ;

} finally {

Systrace.endSection(0L );

}

this .mJavaRegistry.notifyReactBridgeInitialized(bridge) ;

return bridge ;

}

ReactBridge将注册表信息存入与前端互通的全局变量 __fbBatchedBridgeConfig 中,使得Js层与Java层存在同样的模块注册表。bridge.setGlobalVariable是一个native函数。让我们猜一下下它的功能,就是用jsModulesConfig这个参数在js层中生成模块注册表,先看一下参数 buildModulesConfigJSONProperty的代码:

private String buildModulesConfigJSONProperty(NativeModuleRegistry nativeModuleRegistry, JavaScriptModulesConfig jsModulesConfig) {

StringWriter stringWriter = new StringWriter();

JsonWriter writer = new JsonWriter(stringWriter);

String ioe;

try {

writer.beginObject();

writer.name("remoteModuleConfig");

nativeModuleRegistry.writeModuleDescriptions(writer);

writer.name("localModulesConfig");

jsModulesConfig.writeModuleDescriptions(writer);

writer.endObject();

ioe = stringWriter.toString();

} catch (IOException var14) {

throw new RuntimeException("Unable to serialize JavaScript module declaration", var14);

} finally {

try {

writer.close();

} catch (IOException var13) {

;

}

}

return ioe;

}

看到JsonWriter就知道是把NativeModuleRegistry 和JavaScriptModulesConfig 转换成Json字符串,其中remoteModuleConfig指NativeModuleRegistry 信息,localModulesConfig指JavaScriptModulesConfig 信息。看下JavaScriptModulesConfig 的writeModuleDescriptions方法:

public void writeModuleDescriptions(JsonWriter writer) throws IOException {

writer.beginObject();

Iterator i$ = this.mModules.iterator();

while(i$.hasNext()) {

JavaScriptModuleRegistration registration = (JavaScriptModuleRegistration)i$.next();

writer.name(registration.getName()).beginObject();

this.appendJSModuleToJSONObject(writer, registration);

writer.endObject();

}

writer.endObject();

}

看下appendJSModuleToJSONObject方法:

private void appendJSModuleToJSONObject(JsonWriter writer, JavaScriptModuleRegistration registration) throws IOException {

writer.name("moduleID").value((long)registration.getModuleId());

writer.name("methods").beginObject();

Iterator i$ = registration.getMethods().iterator();

while(i$.hasNext()) {

Method method = (Method)i$.next();

writer.name(method.getName()).beginObject();

writer.name("methodID").value((long)registration.getMethodId(method));

writer.endObject();

}

writer.endObject();

if(registration.getModuleInterface().isAnnotationPresent(SupportsWebWorkers.class)) {

writer.name("supportsWebWorkers").value(true);

}

}

从上代码可知生成的json字符串包含moduleID和methodID信息。NativeModuleRegistry 也同理,我们大概看下它的代码:

void writeModuleDescriptions(JsonWriter writer) throws IOException {

Systrace.beginSection(0L, "CreateJSON");

try {

writer.beginObject();

Iterator i$ = this.mModuleTable.iterator();

while(i$.hasNext()) {

NativeModuleRegistry.ModuleDefinition moduleDef = (NativeModuleRegistry.ModuleDefinition)i$.next();

writer.name(moduleDef.name).beginObject();

writer.name("moduleID").value((long)moduleDef.id);

writer.name("supportsWebWorkers").value(moduleDef.target.supportsWebWorkers());

writer.name("methods").beginObject();

for(int i = 0; i < moduleDef.methods.size(); ++i) {

NativeModuleRegistry.MethodRegistration method = (NativeModuleRegistry.MethodRegistration)moduleDef.methods.get(i);

writer.name(method.name).beginObject();

writer.name("methodID").value((long)i);

writer.name("type").value(method.method.getType());

writer.endObject();

}

writer.endObject();

moduleDef.target.writeConstantsField(writer, "constants");

writer.endObject();

}

writer.endObject();

} finally {

Systrace.endSection(0L);

}

}

接下来我们要找到setGlobalVariable的Native层代码,C++层代码我不太懂,这里参考了下别人的分析过程。大概过程是这样,首先入口是OnLoad.cpp。在其中找到如下代码:

void Bridge::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {

runOnExecutorQueue(*m_mainExecutorToken, [=] (JSExecutor* executor) {

executor->setGlobalVariable(propName, jsonValue);

});

}

都是塞进runOnExecutorQueue执行队列里面等待调用,最后回调到JSExecutor,而JSExecutor的实现类是JSCExecutor,最后来看看它的setGlobalVariable方法。

void JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {

auto globalObject = JSContextGetGlobalObject(m_context);

String jsPropertyName(propName.c_str());

String jsValueJSON(jsonValue.c_str());

auto valueToInject = JSValueMakeFromJSONString(m_context, jsValueJSON);

JSObjectSetProperty(m_context, globalObject, jsPropertyName, valueToInject, 0, NULL);

}

懂个大概吧,参数propName是从Java层传递过来的,相当于java代码中的__fbBatchedBridgeConfig和__RCTProfileIsProfiling。jsPropertyName方法就是buildModulesConfigJSONProperty封装好的对象。JSContextGetGlobalObject是WeiKit的方法,接下来会调用到js层的MessageQueue中:

const MessageQueue = require('MessageQueue');

const BatchedBridge = new MessageQueue(

__fbBatchedBridgeConfig.remoteModuleConfig,

__fbBatchedBridgeConfig.localModulesConfig,

);

生成两个映射表,从上面的代码我们己经分析过了,remoteModuleConfig是NativeModuleRegisty映射表内容。localModulesConfig则是JavaScriptModule内容。

到这里,js就生成了两张映射表了,这样java层和js层就都存在同样的映射表,相互通信就是通过它来实现。扯远了,回到createReactView。

第五步

try {

catalystInstance.runJSBundle();

} finally {

Systrace.endSection(0L);

ReactMarker.logMarker("RUN_JS_BUNDLE_END");

}

调用catalystInstance.runJSBundle加载解析Jsbundle。

回到createReactView方法,看catalystInstance.runJSBundle:

public void runJSBundle() {

try {

this.mJSBundleHasLoaded = ((Boolean)this.mReactQueueConfiguration.getJSQueueThread().callOnQueue(new Callable() {

public Boolean call() throws Exception {

Assertions.assertCondition(!CatalystInstanceImpl.this.mJSBundleHasLoaded, "JS bundle was already loaded!");

CatalystInstanceImpl.this.incrementPendingJSCalls();

Systrace.beginSection(0L, "loadJSScript");

try {

CatalystInstanceImpl.this.mJSBundleLoader.loadScript(CatalystInstanceImpl.this.mBridge);

Systrace.registerListener(CatalystInstanceImpl.this.mTraceListener);

} catch (JSExecutionException var5) {

CatalystInstanceImpl.this.mNativeModuleCallExceptionHandler.handleException(var5);

} finally {

Systrace.endSection(0L);

}

return Boolean.valueOf(true);

}

}).get()).booleanValue();

} catch (Exception var2) {

throw new RuntimeException(var2);

}

}

调用catalystInstance.runJSBundle加载解析Jsbundle。假如在解析过程中出现Exception,统一交给NativeModuleCallExceptionHandler处理。

在创建完React Context后会执行ReactContextInitAsyncTask的onPostExecute。来看下onPostExecute的代码:

private void setupReactContext(ReactApplicationContext reactContext) {

UiThreadUtil.assertOnUiThread();

Assertions.assertCondition(this.mCurrentReactContext == null);

this.mCurrentReactContext = (ReactContext)Assertions.assertNotNull(reactContext);

CatalystInstance catalystInstance = (CatalystInstance)Assertions.assertNotNull(reactContext.getCatalystInstance());

catalystInstance.initialize();

this.mDevSupportManager.onNewReactContextCreated(reactContext);

this.mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);

this.moveReactContextToCurrentLifecycleState();

Iterator listeners = this.mAttachedRootViews.iterator();

while(listeners.hasNext()) {

ReactRootView arr$ = (ReactRootView)listeners.next();

this.attachMeasuredRootViewToInstance(arr$, catalystInstance);

}

ReactInstanceEventListener[] var8 = new ReactInstanceEventListener[this.mReactInstanceEventListeners.size()];

var8 = (ReactInstanceEventListener[])this.mReactInstanceEventListeners.toArray(var8);

ReactInstanceEventListener[] var9 = var8;

int len$ = var8.length;

for(int i$ = 0; i$ < len$; ++i$) {

ReactInstanceEventListener listener = var9[i$];

listener.onReactContextInitialized(reactContext);

}

}

这里主要实现两个功能,第一,调用catalystInstance.initialize()来创建NativeModuleRegistry,好啦,回答了一个问题了哈。

public void initialize() {

UiThreadUtil.assertOnUiThread();

Assertions.assertCondition(!this.mInitialized, "This catalyst instance has already been initialized");

this.mInitialized = true;

this.mJavaRegistry.notifyCatalystInstanceInitialized();

}

第二,调用attachMeasuredRootView方法。将ReactRootView做为Root View传递给UIManagerModule,此后Js通过UIManager创建的View都会add到该View上。如下:

public void attachMeasuredRootView(ReactRootView rootView) {

UiThreadUtil.assertOnUiThread();

this.mAttachedRootViews.add(rootView) ;

if( this.mReactContextInitAsyncTask == null && this.mCurrentReactContext != null) {

this .attachMeasuredRootViewToInstance(rootView , this.mCurrentReactContext.getCatalystInstance()) ;

}

}

再来看下attachMeasuredRootViewToInstance这个方法:

private void attachMeasuredRootViewToInstance(ReactRootView rootView , CatalystInstance catalystInstance) {

UiThreadUtil.assertOnUiThread();

rootView.removeAllViews() ;

rootView.setId(- 1);

UIManagerModule uiManagerModule = (UIManagerModule)catalystInstance.getNativeModule(UIManagerModule.class );

int rootTag = uiManagerModule.addMeasuredRootView(rootView) ;

Bundle launchOptions = rootView.getLaunchOptions() ;

WritableMap initialProps = launchOptions != null?Arguments.fromBundle(launchOptions):Arguments.createMap();

String jsAppModuleName = rootView.getJSModuleName() ;

WritableNativeMap appParams = new WritableNativeMap();

appParams.putDouble( "rootTag", ( double)rootTag);

appParams.putMap( "initialProps" , initialProps);

((AppRegistry)catalystInstance.getJSModule(AppRegistry. class)).runApplication(jsAppModuleName, appParams) ;

在绑定完RootView后,通过CatalystInstance获取AppRegistry这个JSModule后,进一步调用runApplication启动Js Application。这个方法的最后用了我们的CatalystInstanceImpl的getJSModule方法,它会去调用JavaScriptModuleRegistry的getJSModule方法,获取对应的JavaScriptModule,也就是从注册表中获取对应的模块。这个地方很新颖,用的是用动态代理方式调用到 JavaScriptModule,具体看JavaScriptModuleInvocationHandler中的invoke方法。

@Override

public @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

ExecutorToken executorToken = mExecutorToken.get();

if (executorToken == null) {

FLog.w(ReactConstants.TAG, "Dropping JS call, ExecutorToken went away...");

return null;

}

String tracingName = mModuleRegistration.getTracingName(method);

mCatalystInstance.callFunction(

executorToken,

mModuleRegistration.getModuleId(),

mModuleRegistration.getMethodId(method),

Arguments.fromJavaArgs(args),

tracingName);

return null;

}

这里获取了调用了方法的moduleId,methodId和参数args,然后调用了CatalystInstanceImpl的callFunction去执行。callFunction也是一个native方法。跟上面的setGlobalVariable流程是一样的,调用的是JSCExecutor的callFunction方法。

void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {

// TODO: Make this a first class function instead of evaling. #9317773

std::vector<:dynamic> call{

moduleId,

methodId,

std::move(arguments),

};

std::string calls = executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));

m_bridge->callNativeModules(*this, calls, true);

}

看下executeJSCallWithJSC方法:

static std::string executeJSCallWithJSC(

JSGlobalContextRef ctx,

const std::string& methodName,

const std::vector<:dynamic>& arguments) {

...

// Evaluate script with JSC

folly::dynamic jsonArgs(arguments.begin(), arguments.end());

auto js = folly::to<:fbstring>(

"__fbBatchedBridge.", methodName, ".apply(null, ",

folly::toJson(jsonArgs), ")");

auto result = evaluateScript(ctx, String(js.c_str()), nullptr);

return Value(ctx, result).toJSONString();

}

如上:

auto js = folly::to<:fbstring>(

"__fbBatchedBridge.", methodName, ".apply(null, ",

folly::toJson(jsonArgs), ")");

用于生成js语名,evaluateScript用于执行js语句。methodName的值为callFunctionReturnFlushedQueue,所以它会调用到MessageQueue.callFunctionReturnFlushedQueue方法,这时就到了js层了:

callFunctionReturnFlushedQueue(module, method, args) {

guard(() => {

this.__callFunction(module, method, args);

this.__callImmediates();

});

return this.flushedQueue();

}

var guard = (fn) => {

try {

fn();

} catch (error) {

ErrorUtils.reportFatalError(error);

}

};

看下__callFunction方法:

_callFunction(module, method, args) {

...

if (isFinite(module)) {

method = this._methodTable[module][method];

module = this._moduleTable[module];

}

...

var moduleMethods = this._callableModules[module];

invariant(

!!moduleMethods,

'Module %s is not a registered callable module.',

module

);

moduleMethods[method].apply(moduleMethods, args);

...

}

通过moduleID和methodID来查询两张映射Table了,获取到了具体的moduleName和methodName,接着肯定要做调用Javascript对应组件了。这样就完成了java层调用js层的module了。说了这么多看下流程图吧:

js与java通信

这里还有一个问题就是反过来的调用 。js调用java的Module。

RN的js调java的流程具体就是是将对应的的参数(moduleId和methodId)push到一个messageQueue中,然后等待java层的事件来驱动它,当java层的事件传递过来时,js层把messageQueue中数据一次性回调给了给java层,最后再通过注册表去调用相应Module的方法。

这里以Toast为例。我们在js层给java层回调参数时会这么写:

RCTToastAndroid.show(message, duration);

而RCTToastAndroid又是NativeModules里的一个属性,最终会调用MessageQueue.RemoteModules:

let modulesConfig = this._genModulesConfig(remoteModules);

this._genModules(modulesConfig);

remoteModules就是上面分析过的,NativeModuleRegistry映射表。看下_genModules方法。

_genModules(remoteModules) {

remoteModules.forEach((config, moduleID) => {

this._genModule(config, moduleID);

});

}

再看下_genModule方法:

_genModule(config, moduleID) {

if (!config) {

return;

}

let moduleName, constants, methods, asyncMethods;

if (moduleHasConstants(config)) {

[moduleName, constants, methods, asyncMethods] = config;

} else {

[moduleName, methods, asyncMethods] = config;

}

let module = {};

methods && methods.forEach((methodName, methodID) => {

const methodType =

asyncMethods && arrayContains(asyncMethods, methodID) ?

MethodTypes.remoteAsync : MethodTypes.remote;

module[methodName] = this._genMethod(moduleID, methodID, methodType);

});

Object.assign(module, constants);

if (!constants && !methods && !asyncMethods) {

module.moduleID = moduleID;

}

this.RemoteModules[moduleName] = module;

return module;

}

主要调用_genMethod方法,它里面实现跳到了__nativeCall方法。所以,说了这么之所有的js最终都会调用到__nativeCall方法。

__nativeCall(module, method, params, onFail, onSucc) {

...

this._callID++;

this._queue[MODULE_IDS].push(module);

this._queue[METHOD_IDS].push(method);

this._queue[PARAMS].push(params);

...

}

将ModuleID和MethodID和要传的参数push到_queue中。

当java事件驱动到来时,调用callFunctionReturnFlushedQueue方法:

callFunctionReturnFlushedQueue(module, method, args) {

guard(() => {

this.__callFunction(module, method, args);

this.__callImmediates();

});

return this.flushedQueue();

}

返回_queue。如上面分析过的,事件驱动到来会执行JSCExecutor的callFunction。最终会执行:

m_callback->onCallNativeModules(getTokenForExecutor(executor), parseMethodCalls(callJSON), isEndOfBatch);

m_callback真正的引用是PlatformBridgeCallback,直接看它的onCallNativeModules方法:

virtual void onCallNativeModules(ExecutorToken executorToken, std::vector&& calls, bool isEndOfBatch) override {

executeCallbackOnCallbackQueueThread([executorToken, calls, isEndOfBatch] (ResolvedWeakReference& callback) {

JNIEnv* env = Environment::current();

for (auto& call : calls) {

makeJavaCall(env, executorToken, callback, call);

if (env->ExceptionCheck()) {

return;

}

}

if (isEndOfBatch) {

signalBatchComplete(env, callback);

}

});

}

...

}

在回调队列线程中执行回调,被执行的回调方法里面对calls进行遍历,分别执行makeJavaCall并把多个执行结果放到一次回调给Native。

env->CallVoidMethod(

callback,

gCallbackMethod,

static_cast(executorToken.getPlatformExecutorToken().get())->getJobj(),

call.moduleId,

call.methodId,

newArray.get());

jclass callbackClass = env->FindClass("com/facebook/react/bridge/ReactCallback");

bridge::gCallbackMethod = env->GetMethodID(callbackClass, "call", "(Lcom/facebook/react/bridge/ExecutorToken;IILcom/facebook/react/bridge/ReadableNativeArray;)V");*>

makeJavaCall将来自Javascript层的moduleId、methodId、args,被调用到Java层的ReactCallback的call方法里面。

java层中,JNI层调用的ReactCallback其实就是NativeModulesReactCallback对象,NativeModulesReactCallback是CatalystInstanceImpl的一个内部类,直接看它的call方法:

public void call(ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters) {

CatalystInstanceImpl.this.mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread();

synchronized(CatalystInstanceImpl.this.mJSToJavaCallsTeardownLock) {

if(!CatalystInstanceImpl.this.mDestroyed) {

CatalystInstanceImpl.this.mJavaRegistry.call(CatalystInstanceImpl.this, executorToken, moduleId, methodId, parameters);

}

}

}

mJavaRegistry就是java层保存的NativeModuleRegistry映射表,这里就是通过Js传过来moduleId, methodId来匹配方法,看下它的call方法:

void call(CatalystInstance catalystInstance, ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters) {

NativeModuleRegistry.ModuleDefinition definition = (NativeModuleRegistry.ModuleDefinition)this.mModuleTable.get(moduleId);

if(definition == null) {

throw new RuntimeException("Call to unknown module: " + moduleId);

} else {

definition.call(catalystInstance, executorToken, methodId, parameters);

}

}

ModuleDefinition则是NativeModuleRegistry的一个内部类,mModuleTable是保持着NativeModule的映射表,通过get方法获得所有调用的Module,在这里就是ToastModule。看下ModuleDefinition的call方法:

public void call(CatalystInstance catalystInstance, ExecutorToken executorToken, int methodId, ReadableNativeArray parameters) {

NativeModuleRegistry.MethodRegistration method = (NativeModuleRegistry.MethodRegistration)this.methods.get(methodId);

Systrace.beginSection(0L, method.tracingName);

try {

((NativeModuleRegistry.MethodRegistration)this.methods.get(methodId)).method.invoke(catalystInstance, executorToken, parameters);

} finally {

Systrace.endSection(0L);

}

}

ModuleDefinition是NativeModule内方法信息的封装类,代码也在NativeModuleRegistry中。

private static class MethodRegistration {

public String name;

public String tracingName;

public NativeMethod method;

public MethodRegistration(String name, String tracingName, NativeMethod method) {

this.name = name;

this.tracingName = tracingName;

this.method = method;

}

}

NativeModule.NativeMethod对象,真正的实现则是JavaMethod类,所以this.methods.get(methodId)).method.invoke最终是调用javaMethod的invoke方法。

public void invoke(CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray parameters) {

SystraceMessage.beginSection(0L, "callJavaModuleMethod").arg("method", this.mTraceName).flush();

try {

if(this.mJSArgumentsNeeded != parameters.size()) {

throw new NativeArgumentsParseException(BaseJavaModule.this.getName() + "." + this.mMethod.getName() + " got " + parameters.size() + " arguments, expected " + this.mJSArgumentsNeeded);

}

int i = 0;

int jsArgumentsConsumed = 0;

byte executorTokenOffset = 0;

if(BaseJavaModule.this.supportsWebWorkers()) {

this.mArguments[0] = executorToken;

executorTokenOffset = 1;

}

try {

while(i < this.mArgumentExtractors.length) {

this.mArguments[i + executorTokenOffset] = this.mArgumentExtractors[i].extractArgument(catalystInstance, executorToken, parameters, jsArgumentsConsumed);

jsArgumentsConsumed += this.mArgumentExtractors[i].getJSArgumentsNeeded();

++i;

}

} catch (UnexpectedNativeTypeException var17) {

throw new NativeArgumentsParseException(var17.getMessage() + " (constructing arguments for " + BaseJavaModule.this.getName() + "." + this.mMethod.getName() + " at argument index " + this.getAffectedRange(jsArgumentsConsumed, this.mArgumentExtractors[i].getJSArgumentsNeeded()) + ")", var17);

}

try {

this.mMethod.invoke(BaseJavaModule.this, this.mArguments);

} catch (IllegalArgumentException var14) {

throw new RuntimeException("Could not invoke " + BaseJavaModule.this.getName() + "." + this.mMethod.getName(), var14);

} catch (IllegalAccessException var15) {

throw new RuntimeException("Could not invoke " + BaseJavaModule.this.getName() + "." + this.mMethod.getName(), var15);

} catch (InvocationTargetException var16) {

if(var16.getCause() instanceof RuntimeException) {

throw (RuntimeException)var16.getCause();

}

throw new RuntimeException("Could not invoke " + BaseJavaModule.this.getName() + "." + this.mMethod.getName(), var16);

}

} finally {

Systrace.endSection(0L);

}

}

上面代码中,从js层传过来的参数被封装到mArguments中,最后调用以下代码来完成 最终操作:

this.mMethod.invoke(BaseJavaModule.this, this.mArguments);

BaseJavaModule.this指代当前NativeModule对象的实例,如果是Toast组件的话就是ToastModule了,利用反射就找到了ToastModule模块。到此,js调用java流程就完成了。画了个流程图方便理解:

总结

最后来对这篇文章做一个总结。

在程序启动的时候,首先会调用ReactActivity的onCreate函数中,我们会去创建一个ReactInstanceManagerImpl对象。通过ReactRootView的startReactApplication方法开启整个RN世界的大门。 在这个方法中,我们会通过一个AsyncTask去创建ReactContext 在创建ReactContext中,我们把我们自己注入和CoreModulesPackage通过processPackage方法将其中的各个modules注入到了对应的Registry中。最后通过CatalystInstanceImpl中的ReactBridge将NativeModule和JSModule注册表通过jni传输到了JS层。 java调用js时,会在ReactApplicationContext创建的时候存入注册表类JavaScriptModuleRegistry中,同时通过动态代理生成代理实例,并在代理拦截类JavaScriptModuleInvocationHandler中统一处理发向Javascript的所有通信请求。 JSCExecutor将所有来自Java层的通信请求封装成Javascript执行语句。 接着在js层中的MessageQueue里匹配ModuleId和MethodId。找到调用模块。 如果是js层调用java层,js最终都会调用__nativeCall方法,通过flushedQueue将this._queue返回给Bridger。 C++层调用PlatformBridgeCallback对象的onCallNativeModules方法,执行makeJavaCall方法,里面最终通过env->CallVoidMethod调用了Java层的方法。 调用Java层NativeModulesReactCallback的call方法,通过moduleID从保存在其内部的NativeModule映射表,匹配到需要被执行的NativeModule对象,再通过methodID匹配到所要调用的方法。通过invoke反射方式执行NativeModule的方法。

ReactNative的源码流程就分析完了,当然还有很多不懂的地方,以后学习中再争取弄懂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值