React Native 与原生层通讯(Android)

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 来访问的方法。

自定义 Module 代码:

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 原生层通讯之后,你就可以自己扩展封装一些组件供自己所用了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值