本文还是基于
React Native通讯原理
理解的一份个人笔记形式的博客
1.先上通讯总体框架图
2.再上Native调用JS的流程图
下面结合上面的图再结合ReactNative源码加以理解分析
那么我们结合源码看看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原型产生动态代理供给使用,而限制我们要把这些收集的接口
在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;
}
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);
},
};
// 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);
},
};
但是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;
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记录了原生模块的名字的集合,
现在我的疑问是那个记录模块名称和记录记录模块集合的
ModuleRegistry是在哪里放入进去的呢?
其实这是在CatalysInstance实例时发生的,请看
我们调用了这个 getModuleRegistryHolder,那么我们看看getModuleRegistryHolder,
- private CatalystInstanceImpl(
- ...
- mJavaRegistry.getModuleRegistryHolder(this));
- @H_502_946@mMainExecutorToken = getMainExecutorToken();
- }
继续看看 ModuleRegistryHolder的构造函数
- /* package */ ModuleRegistryHolder getModuleRegistryHolder(
- CatalystInstanceImpl catalystInstanceImpl) {
- ...
- return new ModuleRegistryHolder(catalystInstanceImpl,javaModules,cxxModules);
- }
- 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);
- }
- }
另外我们注意:
关于Native接受JS调用
产生JSOn,通过JstoNative调用到java