菜鸟学习React Native for Android 之通讯原理分析(JS调用Nativ
发布时间:2020-12-15 08:19:50 所属栏目:百科 来源:网络整理
导读:本文还是基于 React Native通讯原理 理解的一份个人笔记形式的博客 1.先上通讯总体框架图 2.再上Native调用JS的流程图 下面结合上面的图再结合ReactNative源码加以理解分析 思路分析:对于JS调用native来说,RN官方的思路是收集JAVA MODULE,在JS端生成一个JS
本文还是基于React Native通讯原理理解的一份个人笔记形式的博客
1.先上通讯总体框架图
2.再上Native调用JS的流程图
下面结合上面的图再结合ReactNative源码加以理解分析
思路分析:对于JS调用native来说,RN官方的思路是收集JAVA MODULE,在JS端生成一个JS对象,这个JS对象和这个JAVA模块类名相同或者相关,
这个JS对象再生成和native同名的function,例如这也 JSobj.methodname=function,于是在JS端就可以 调用这个JS的对象方法,而这个JS对象的每个方法
内部其实是负责把方法调用信息传递的messagequeue,然后调用JSCEExecutor注册在javascritCore的方法,传递给C++端,
C++端则根据JNI技术,结合反射可以调用到JAVA的方法,从而JavaModule中的方法得到执行。
那么我们结合源码看看JS是如何收集JAVA模型的呢,JAVA模型的根本来源还是在于Package包里面,例如MainReactPackage的getNativeModules,
在这里提供了
@Override public List<ModuleSpec> getNativeModules(final ReactApplicationContext context) { return Arrays.asList( new ModuleSpec(AppStateModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new AppStateModule(context); } }),new ModuleSpec(AsyncStorageModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new AsyncStorageModule(context); } }),new ModuleSpec(CameraRollManager.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new CameraRollManager(context); } }),new ModuleSpec(ClipboardModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new ClipboardModule(context); } }),new ModuleSpec(DatePickerDialogModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new DatePickerDialogModule(context); } }),new ModuleSpec(DialogModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new DialogModule(context); } }),new ModuleSpec(FrescoModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new FrescoModule(context); } }),new ModuleSpec(I18nManagerModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new I18nManagerModule(context); } }),new ModuleSpec(ImageEditingManager.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new ImageEditingManager(context); } }),new ModuleSpec(ImageLoaderModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new ImageLoaderModule(context); } }),new ModuleSpec(ImageStoreManager.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new ImageStoreManager(context); } }),new ModuleSpec(IntentModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new IntentModule(context); } }),new ModuleSpec(LocationModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new LocationModule(context); } }),new ModuleSpec(NativeAnimatedModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new NativeAnimatedModule(context); } }),new ModuleSpec(NetworkingModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new NetworkingModule(context); } }),new ModuleSpec(NetInfoModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new NetInfoModule(context); } }),new ModuleSpec(PermissionsModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new PermissionsModule(context); } }),new ModuleSpec(ShareModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new ShareModule(context); } }),new ModuleSpec(StatusBarModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new StatusBarModule(context); } }),new ModuleSpec(TimePickerDialogModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new TimePickerDialogModule(context); } }),new ModuleSpec(ToastModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new ToastModule(context); } }),new ModuleSpec(VibrationModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new VibrationModule(context); } }),new ModuleSpec(WebSocketModule.class,new Provider<NativeModule>() { @Override public NativeModule get() { return new WebSocketModule(context); } })); }
和之前分享JAVA调用JS类似,也是在ReactInstanceManager的
processPackage方法里面把这些注册到CatalysInstance包含的NativeModuleRegistry里面
之前分析JS调用java的时候我们是从收集到的JS在JAVA原型产生动态代理供给使用,而限制我们要把这些收集的接口
RN在javaScriptCore设置了一个全局性的属性,__fbBatchedBridgeConfig,属性的值就是native module name列表。
在NativeModule.js中有这么一段是用来根据收集的JAVA模型信息产生JS funciion的
let NativeModules : {[moduleName: string]: Object} = {};
if (global.nativeModuleProxy) { NativeModules = global.nativeModuleProxy; } else { const bridgeConfig = global.__fbBatchedBridgeConfig; invariant(bridgeConfig,'__fbBatchedBridgeConfig is not set,cannot invoke native modules'); (bridgeConfig.remoteModuleConfig || []).forEach((config: ModuleConfig,moduleID: number) => { // Initially this config will only contain the module name when running in JSC. The actual // configuration of the module will be lazily loaded. const info = genModule(config,moduleID); if (!info) { return; }
实际使用是这样的:
class AwesomeProject extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome} onPress={onClick} >
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started,edit index.android.js
</Double tap R on your keyboard to reload,{'n'}
Shake or press menu button for dev menu
</TextInput />
</View>
);
}
}
function onClick(){
var ToastAndroid = require('ToastAndroid')
ToastAndroid.show('Click TextView...',ToastAndroid.SHORT);
}
而show实际是是这样的
var RCTToastAndroid = require('NativeModules').ToastAndroid;
var ToastAndroid = {
// Toast duration constants SHORT: RCTToastAndroid.SHORT, LONG: RCTToastAndroid.LONG, // Toast gravity constants TOP: RCTToastAndroid.TOP, BOTTOM: RCTToastAndroid.BOTTOM, CENTER: RCTToastAndroid.CENTER, show: function ( message: string, duration: number ): void { RCTToastAndroid.show(message,duration); }, showWithGravity: function ( message: string, duration: number, gravity: number, ): void { RCTToastAndroid.showWithGravity(message,duration,gravity); }, };
调用的正是我们在nativeModules生成的对应JAVA接口的function,然后传回C++端,反射调用相应的JAVA实现
但是JS是如何拿到Native模块的详细信息的呢?
let NativeModules : {[moduleName: string]: Object} = {};
if (global.nativeModuleProxy) { NativeModules = global.nativeModuleProxy; } else { const bridgeConfig = global.__fbBatchedBridgeConfig; invariant(bridgeConfig,cannot invoke native modules'); (bridgeConfig.remoteModuleConfig || []).forEach((config: ModuleConfig,moduleID: number) => { // Initially this config will only contain the module name when running in JSC. The actual // configuration of the module will be lazily loaded. const info = genModule(config,moduleID); if (!info) { return; } remoteModuleConfig if (info.module) { NativeModules[info.name] = info.module; } // If there's no module config,define a lazy getter else { defineLazyObjectProperty(NativeModules,info.name,{ get: () => loadModule(info.name,moduleID) }); } }); } module.exports = NativeModules;
bridgeConfig记录了原生模块的名字的集合,
第一句 const info = genModule(config,moduleID);这个是产生了一个info对象,有一个name属性,值就是模块名称
loadModule其实是调用了JSCExecutor在javascriptScore注册的一个函数,nativeRequireModuleConfig,
根据这个方法我们从ModuleRegistry中获取模块的详细信息
现在我的疑问是那个记录模块名称和记录记录模块集合的
ModuleRegistry是在哪里放入进去的呢?
其实这是在CatalysInstance实例时发生的,请看
private CatalystInstanceImpl( ... mJavaRegistry.getModuleRegistryHolder(this)); mMainExecutorToken = getMainExecutorToken(); }我们调用了这个 getModuleRegistryHolder,那么我们看看getModuleRegistryHolder, /* package */ ModuleRegistryHolder getModuleRegistryHolder( CatalystInstanceImpl catalystInstanceImpl) { ... return new ModuleRegistryHolder(catalystInstanceImpl,javaModules,cxxModules); }继续看看 ModuleRegistryHolder的构造函数 public class ModuleRegistryHolder { private final HybridData mHybridData; private static native HybridData initHybrid( CatalystInstanceImpl catalystInstanceImpl,Collection<JavaModuleWrapper> javaModules,Collection<CxxModuleWrapper> cxxModules); public ModuleRegistryHolder(CatalystInstanceImpl catalystInstanceImpl,Collection<CxxModuleWrapper> cxxModules) { mHybridData = initHybrid(catalystInstanceImpl,cxxModules); } } 看到了吧 我们调用了JNI native initHybrid方法,把模块信息传递到C++了。
另外我们注意:
关于Native接受JS调用
1.
主动,调用指令会传递到MESSAGEQUEUE,然后准备调用JSC注册到ajvaScriptCore的方法,先判断上次调用的时候和本次调用的时间如果超过
5ms就调用,QUEUE传递过去后,产生JSON字符串,通过JstoNative调用到java
2.
被动,在某个适当的时候,具体啥时目前不清楚,会通过JSC调用到QUEUE在JAVAScriptCore注册的f方法,从而执行到JS里,然后把queue中剩余指令刷过去,
产生JSOn,通过JstoNative调用到java
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |