React native 中原生层与js数据交互的几种方式

想第一时间获取我的最新文章,请关注公众号: 技术特工队

技术特工队

RN 方法的调用的几种方法

从数据的交互上来看,调用方无非从 native 调用 js 层,或 从 js 调用 native 方法,常用的主要是通过 JavaModule 来提供方法调动,但常常我们有一些自定义的native view,而这部分也是需要和 js进行相关的交互,那么下面进行调用的一些统一的整理。

js 调用 native 方法

js 通过 JavaModule 方式进行调用。

在 RN 中需要调用 native 的方法,常用的是通过在 native 继承 ReactContextBaseJavaModule 然后注册 ReactMethod 方法,供js层进行调用。
例如:

1
2
3
4
5
6
7
8
9
10
11
12
public class ToastWidget extends ReactContextBaseJavaModule {

@Override
public String getName() {
return "ToastWidget";
}

@ReactMethod
public void showToast(String message) {
Toast.makeText(getCurrentActivity(), message, Toast.LENGTH_SHORT).show();
}
}

然后此 module 在 ReactPackage 中进行注册,最后此package在 Application 中进行注册处理。

在 js 中 可以按如下方式即可调用 native 层的方法。

1
2
3
4
import {  NativeModules } from 'react-native'
const { ToastWidget } = NativeModules

ToastWidget.showToast('这是一个Toast')

自定义native view,js 如果调用native view中的方法

常常在native层需要实现一些 js 无法达到效果或者满足需求的界面,这时候就需要native层自定义view来实现了,而这部分 RN 提供了ViewManger 来满足需求,那如何在自定义view中的方法能够让 js 调用呢,一般的可以通过props进行控制,如果是一些特殊的方法呢,RN提供了getCommandsMapreceiveCommand 两个方法来实现,js调用viewManger中的方法,commands 为提供的命令集合,receiveCommand接收命名,并执行相应的native代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
public Map<String, Integer> getCommandsMap() {
// 导出 command
return MapBuilder.<String, Integer>builder()
.put("scrollTo", COMMAND_SCROLL_TO)
.put("atUser", COMMAND_AT_USER)
.build();
}

@Override
public void receiveCommand(@Nonnull ChatView root, int commandId, @Nullable ReadableArray args) {
// 根据命令执行对应的native方法
switch (commandId) {
case COMMAND_SCROLL_TO:
Logger.v(MODULE_NAME, "receiveCommand scroll to args = " + args);
break;
case COMMAND_AT_USER:
Logger.v(MODULE_NAME, "receiveCommand at user args = " + args);
break;
default:
Logger.v(MODULE_NAME, "receiveCommand not found args = " + args);
break;
}
}

在js中可使用如下进行调用:

1
2
3
4
5
6
7
// 导入native view ,进行布局显示
const NativeView = requireNativeComponent('NativeView')
UIManager.dispatchViewManagerCommand(
findNodeHandle(this._chatViewRef), // _chatViewRef 为native view的引用
NativeView.Commands.scrollTo, // 对应native层getCommandsMap定义
args, // 参数,参数为数组对象
)

通过上面代码即可实现 js层调用自定义 view 中的方法了。

native 调用 js 方法

这部分主要是传递 native 的回调事件及数据给到js或者直接调用js层的方法。

native 回调数据给到js层

这部分常见于注册一些native的listener接口,后续数据有变化后,在通过RCTDeviceEventEmitter此部分给到js层,示例如下:

1
2
3
4
5
context.runOnNativeModulesQueueThread(() -> {
// 获取deviceEventmanager 然后发送事件及数据
DeviceEventManagerModule.RCTDeviceEventEmitter emitter = context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
emitter.emit(eventName, message); // eventName 为事件名, message为具体的消息内容,需要为RN支持的数据类型
});

在 js层添加数据的监听,监听数据的变化

1
2
3
4
import { NativeModules, NativeEventEmitter } from 'react-native'

const nativeEventEmitter = new NativeEventEmitter("nativeModuleName")
return nativeEventEmitter.addListener("eventName", listener) // eventName 为上层发送的事件名, listener 为添加的事件监听函数

这种方案即可实现数据的监听。

native直接调用js中的方法

这种操作一般是在界面层,想要直接调用js中的方法而进行的操作,native层在继承自 SimpleViewManager 中复写 addEventEmitters 方法,定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
protected void addEventEmitters(@Nonnull ThemedReactContext reactContext, @Nonnull CustomView view) {
// 这里添加调用的执行方法
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
view.getId(),
"EVENT_METHOD_1", // 调用js的方法名
data // 调用传递的数据
);
}

@Nullable
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
//注册支持的调用的方法名
return MapBuilder.<String, Object>builder()
.put("EVENT_METHOD_1", MapBuilder.of("registrationName", "EVENT_METHOD_1"))
.put("EVENT_METHOD_2", MapBuilder.of("registrationName", "EVENT_METHOD_2"))
.build();
}

addEventEmitters的方法参数中能够拿到自定义的View,所以这里可以设置一个回调函数给到View,当View调用方法后,这里就可以直接调用相关方法到js层,接下来再来看下js层要如何处理。

在js中按照属性的方式进行设置方法,如下:

1
2
3
4
5
6
7
8
9
10
_eventMethode(event) {
console.log('_eventMethode event = ', event.nativeEvent)
}

<NativeCustomView
ref={this._createViewRef}
style={styles.container}
eventMethod1={this._eventMethode}
eventSendMessage={this._eventMethode}
/>

在js层eventMethod1可以理解为属性,但在这里为 native 层中向下调用的方法名,native 调用过则会回调到此方法传递的方法,也就是_eventMethode方法,
这样在native中执行 addEventEmitters方法中 “EVENT_METHOD_1” ,即可实现调用 js 层的_eventMethode方法

总结

要实现 js 与 native 的互相通信,则必不可少会有这些操作,所以在什么情况下使用什么方式进行数据传递或方法的调用需考虑清楚。以上几种方式基本上涵盖了大部分的消息数据通信的场景。

WangXin wechat
欢迎订阅我的微信公众号,第一时间获取最新文章!
坚持原创技术分享,您的支持将鼓励我继续创作!