React Native开发中不可避免涉及到到同原生交互通讯,FB 官方封装了一系列的跨平台组件,但是总是不能面面俱到的,所以很多组件还是需要我们自己去封装,实现同原生层交互。
Android自定义扩展包括两部分,一个是module,一个是View,这两个部分js层同其交互方法有所不同。
1. RN 同 Module 通讯
步骤一:创建一个 BaseModule 的抽象类,BaseModule 继承自ReactContentBaseJavaModule,然后在内部定义一个方法sendEvent,用来向js层发送数据,当其它 Android 模块继承 BaseModule,可以直接调用 sendEvent 方法,发送数据给 js 层,js 只需要监听对应方法名,就可以获得发送过来的值。
BaseModule代码:
- package com.test;
-
- import android.support.annotation.Nullable;
-
- import com.facebook.react.bridge.ReactApplicationContext;
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
- import com.facebook.react.bridge.WritableMap;
- import com.facebook.react.modules.core.DeviceEventManagerModule;
-
- abstract public class BaseModule extends ReactContextBaseJavaModule {
-
- protected ReactApplicationContext context;
-
- public BaseModule(ReactApplicationContext reactContext) {
- super(reactContext);
- context = reactContext;
- }
-
- /** * 原生层向js层发送数据 * @param eventName * @param params */
- protected void sendEvent(String eventName,@Nullable WritableMap params) {
- context
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
- .emit(eventName,params);
- }
- }
步骤二:然后创建一个 Android 模块继承 BaseModule,然后使用 @ReactMethod 来标记那些你希望通过Js来访问的方法。
- package com.test;
-
- import com.facebook.react.bridge.ReactApplicationContext;
-
- public class TestModule extends BaseModule {
-
- public TestModule(ReactApplicationContext reactContext) {
- super(reactContext);
- context = reactContext;
- }
-
- @Override
- public String getName() {
- return "Test";
- }
-
- @ReactMethod
- public void test(String text) {
- WritableMap event = Arguments.createMap();
- event.putString("text",text);
- sendEvent("testEvent",event);
- }
- }
步骤三:最后在 js 层调用 native 层方法,并监听 native 返回。一般写第三方模块的话会写一个 index.js 文件,统一实现这些方法。使用DeviceEventEmitter.addListener监听native层返回,若只是想触发一次监听,那可以使用DeviceEventEmitter.once。
- import {
- NativeModules,DeviceEventEmitter
- } from 'react-native';
-
- const listeners = {};
- const TestModule = NativeModules.Test;
-
- export default class Test {
-
- static test(text) {
- TestModule.test(text);
- }
-
- static addTestListener(cb) {
- listeners[cb] = DeviceEventEmitter.addListener('testEvent',resp => {
- cb(resp);
- });
- }
-
- static removeTestListener(cb) {
- if (!listeners[cb]) {
- return;
- }
- listeners[cb].remove();
- listeners[cb] = null;
- }
- }
2. RN 同 View 通讯
步骤一: 继承自ViewGroupManager,使用 @ReactProp(name = “xx”) 来传递props值到native层中,如果想通过方法从 js 层传值过来,就需要在 native 层重写 getCommandsMap 和 receiveCommand,在 receiveCommand 通过 type 值获得从 js 层不同调用传递过来的数据 。
- package com.test;
-
- import android.support.annotation.Nullable;
-
- import com.facebook.react.bridge.Arguments;
- import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
- import com.facebook.react.bridge.ReadableArray;
- import com.facebook.react.bridge.ReadableMap;
- import com.facebook.react.bridge.WritableMap;
- import com.facebook.react.common.MapBuilder;
- import com.facebook.react.uimanager.ThemedReactContext;
- import com.facebook.react.uimanager.ViewGroupManager;
- import com.facebook.react.uimanager.annotations.ReactProp;
- import com.facebook.react.uimanager.events.RCTEventEmitter;
- import com.facebook.react.views.view.ReactViewGroup;
-
- import java.util.Map;
-
- /** * Created by chenwenyu on 17-8-27. */
-
- public class TestViewManager extends ViewGroupManager<MyCustomView> {
-
- private ThemedReactContext mReactContext;
-
- public static final int UPDATE_DATA = 1;
-
- @Override
- public String getName() {
- return "TestView";
- }
-
- @Override
- protected MyCustomView createViewInstance(ThemedReactContext reactContext) {
- mReactContext = reactContext;
- return new MyCustomView(reactContext);
- }
-
- @Override
- public Map<String,Integer> getCommandsMap() {
- return MapBuilder.of(
- "updateData",TestViewManager.UPDATE_DATA
- );
- }
-
- @Override
- public void receiveCommand(MyCustomView view,int commandType,@Nullable ReadableArray args) {
-
- switch (commandType) {
- case TestViewManager.UPDATE_DATA:
- updateData(view,args.getMap(0));
- break;
- default:
- throw new JSApplicationIllegalArgumentException(String.format(
- "Unsupported commadn %d received by $s",commandType,this.getClass().getSimpleName()
- ));
- }
- }
-
- @ReactProp(name = "visibility")
- public void setVisibility(ReactViewGroup reactViewGroup,int visibility) {
- reactViewGroup.setVisibility(visibility);
- }
-
- /** * 原生层向js层发送数据 * @param eventName * @param params */
- private void sendEvent(MyCustomView myCustomView,String eventName,@Nullable WritableMap params) {
- WritableMap event = Arguments.createMap();
- event.putMap("params",params);
- event.putString("type",eventName);
- mReactContext
- .getJSModule(RCTEventEmitter.class)
- .receiveEvent(myCustomView.getId(),"topChange",event);
- }
-
- private void updateData(MyCustomView myCustomView,ReadableMap option) {
- if (option != null) {
- String data = option.getString("data");
- data += "data:" + data;
- WritableMap writableMap = Arguments.createMap();
- writableMap.putString("callData",data);
- sendEvent(myCustomView,"test",writableMap);
- }
- }
- }
步骤二:js层调用,可以通过直接设置props的值向原生层传递值,也可以通过dispatchViewManagerCommand传递值
- import {
- requireNativeComponent
- } from 'react-native';
-
- import React,{
- PureComponent
- } from 'react';
-
- import react_native from 'react-native';
- var RCTTestView = react_native.UIManager.TestView;
- var Commands = RCTTestView.Commands;
- var COMMAND_UPDATE_DATA = Commands.updateData; //同原生层getCommandsMap相对应
-
- export default class TestView extends PureComponent {
-
- constructor() {
- super();
- }
-
- _onChange(event) {
- if (typeof this.props[event.nativeEvent.type] === 'function') {
- this.props[event.nativeEvent.type](event.nativeEvent.params);
- }
- }
-
- updateData(data) {
- react_native.UIManager.dispatchViewManagerCommand(react_native.findNodeHandle(this),COMMAND_UPDATE_DATA,[data]);
- }
-
- render() {
- return <TestShowView visibility={1} onChange={this._onChange.bind(this)}/>;
- }
- }
-
- const TestShowView = requireNativeComponent('TestView',TestView,{
- nativeOnly: {
- onChange: true
- }
- });
当了解了 js 层同 Android 原生层通讯之后,你就可以自己扩展封装一些组件供自己所用了。