React Native源碼分析(二):Native和JS通信

語言: CN / TW / HK

theme: channing-cyan

系列文章

React Native源碼分析(一):環境初始化以及Bundle加載

Native調用JS方法

首先在Native側,會引入一系列接口,這些接口繼承自JavaScriptModule接口,這些接口表示JS中同名模塊的接口,調用Native側接口中的方法就相當於調用JS同名模塊中對應的方法,以Android啟動項目訪問JS側的AppRegistry模塊的runApplication為例。

RNNative調用jsjava.jpg

先看一下在Native側調用在ReactRootView中調用runApplication方法,接着通過CatalysInstancempl獲取AppRegistry的實現類,這個實現類實際上是在JavaScriptModuleRegistry通過動態代理在JavaScriptModuleInvocationHandler中實現的,最終會回調CatalyInstanceImpl的jniCallJSFunction方法,將js側的module名稱,method名稱和參數傳入進去,之後就進入C++的流程了。

native到jsc++.jpg CatalyInstanceImpl.cpp首先調用了Instance的callJSFunction,接着Instance會調用NatieToJsBridge的callFunction,然後調用MessageQueueThread的runOnQueue方法,MessageThread是在Java側初始化CatalyInstanceImpl的時候創建ReactQueueConfigurationImpl時創建的MessageQueueThread,在這裏會有創建三個MessageQueueThread,一個js線程,用來native調用js方法,一個native線程,用來js調用native方法,一個UI線程,每個MessageQueueThread都有以個Looper和Handler。MessageQueueThread的runOnQueue方法會將一個runnable方法注入java側Looper,等到調用時會調用JSIExecutor的callFunction方法,這個JSIExecutor實際上可以粗略理解為js引擎,通過模板注入不同的js側運行時runtime實現和js引擎的解耦。JSIExecutor調用在js側MessageQueue模塊實現的callFunctionReturnedFlushedQueue方法,傳入js模塊名、方法名和參數,完成js側的方法調用後,然後會調用JSIExecutor的callNativeModules方法,將js調用native隊列中的所有方法進行一遍調用,同時回調Native側的onBathCompleted方法,至此Native到js側方法的調用流程就結束了。

JS調用Native方法

創建NativeModules信息

js到native通信創建native模塊.jpg

java側ReactInstanceManager在創建ReactContext的時候會處理所有注入的ReactPackage,解析其中所有的createNativeModules方法返回的NativeModuleHolder map,並且通過NativeModuleRegistry持有所有該list對象,通過CatalyInstanceImpl創建的時候在調用initlizedBridge方法時進入c++側,同時傳入的所有JavaModuleWrapper的list和C++的本地方法的ModuleHolder list。根據傳入的JavaModuleWrapper的list和ModuleHoder的list,創建C++本地的ModuleRegistry.cpp,然後通過initializeRuntime方法調用NativeToJsBidge的方法,NativeToJsBridge持有JSIExecutor,調用它的initializeRuntime方法,然後設置NativeModuleProxy為js側對應的nativeModuleProxy對象,最終會賦值給js側的NativeModules對象,NativeModules其實就是一個map,而NativeModuleProxy會持有JSINativeModules,其中JSINativeModules會持有之前創建的本地C++ ModuleRegistry對象,而ModuleRegistry包含所有的NativeModules信息,至此NativeModules信息構建完成。

調用Native方法

js到native通信2.jpg 前面説過,NativeModules.js對應的實現其實就是C++側的NativeModuleProxy.cpp,所以NativeModules.ModuleName其實就是訪問NativeModuleProxy的get方法,NativeModuleProxy持有了JSINativeModules,然後調用NativeModuleProxy的getModule方法,在這裏會有一個混竄邏輯,如果之前已經創建過對應的NativeModule,那麼直接返回,否則就會調用ModuleRegistry的getConfig方法用來獲取對應NativeModule的配置信息,這個配置信息包含Module名稱、native暴露給js側的常量,方法名數組以及異步方法id數組和同步方法id數組。這些信息的獲取其實是通過Native側的JavaModuleWrapper.java實現的,通過調用它的一些列對應方法,獲取相應的NativeModule的配置信息,而這些配置信息最終會寫入js側的NativeModules裏,前面説過,NativeModules就是一個map。調用NativeModules的異步方法時最終會調用到MessageQueue.enqueueNativeCall方法,最終會通過NativeToJsBridge.cpp調用Native側的JavaModuleWrapper的invoke方法,這裏就會根據methodId找到在NativeModule中用@ReactMethod標註的對應的方法,然後進行最終的調用。

關注我的公眾號:‘滑板上的老砒霜'