ReactNative调用Android原生模块参数回传方法详解

Viewed 0

在上一篇文章中,我们简单尝试了React Native向Android原生传递参数并调用Android方法。本文将介绍Android如何向React Native回传参数,即实现回调功能。

Android向React Native回传参数主要有以下几种方式:

  1. Callback
  2. Promises
  3. RCTDeviceEventEmitter(适用于多线程场景)

为了快速掌握核心用法,本文重点介绍第1种和第3种方式。第二种方式Promises的用法类似,可参考React Native官方文档。此外,本文还将演示如何从React Native启动原生Activity。

实现步骤

以下步骤延续自之前的项目,假设已创建React Native项目并配置了基础环境。

1. 创建原生模块类

首先,创建一个继承自ReactContextBaseJavaModule的类,例如TestModules。在该类中定义相关方法。

public class TestModules extends ReactContextBaseJavaModule {
    private ReactApplicationContext mContext;

    public TestModules(ReactApplicationContext reactContext) {
        super(reactContext);
        mContext = reactContext;
    }

    @Override
    public String getName() {
        // 此名称用于在React Native中调用
        return "TestModules";
    }

    /**
     * 从React Native调用原生模块,支持传递多种参数类型:
     * Boolean -> Bool
     * Integer -> Number
     * Double -> Number
     * Float -> Number
     * String -> String
     * Callback -> function
     * ReadableMap -> Object
     * ReadableArray -> Array
     */
    @ReactMethod
    public void Toasts(ReadableMap msg) {
        ReadableNativeMap map = (ReadableNativeMap) msg;
        HashMap map2 = map.toHashMap();
        Toast.makeText(mContext, (String) map2.get("name"), Toast.LENGTH_SHORT).show();
    }

    /**
     * Android向React Native回传参数(使用Callback)
     */
    @ReactMethod
    public void ToastFinished(String msg, Callback callback) {
        Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
        WritableMap map = Arguments.createMap();
        map.putInt("id", 1);
        map.putString("name", "小明");
        WritableArray array = Arguments.createArray();
        array.pushString("哈哈1");
        array.pushString("哈哈2");
        map.putArray("sub", array);
        callback.invoke(map);
    }

    /**
     * Android向React Native发送事件(使用RCTDeviceEventEmitter)
     */
    @ReactMethod
    public void sendEvent() {
        WritableMap map = Arguments.createMap();
        map.putInt("id", 1);
        map.putString("name", "路人甲");
        mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("sendEvent", map);
    }

    /**
     * 启动原生Activity
     */
    @ReactMethod
    public void startActivity() {
        Intent intent = new Intent(mContext, TestModuleActivity.class); // 确保在AndroidManifest.xml中注册Activity
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
    }
}

2. 实现ReactPackage

创建一个实现ReactPackage接口的类,用于注册原生模块。

public class TestPackages implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> nativeModules = new ArrayList<>();
        nativeModules.add(new TestModules(reactContext));
        return nativeModules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

3. 注册到MainApplication

MainApplication类中添加自定义的ReactPackage

public class MainApplication extends Application implements ReactApplication {
    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
            return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
            return Arrays.<ReactPackage>asList(
                    new MainReactPackage(),
                    new TestPackages()
            );
        }

        @Override
        protected String getJSMainModuleName() {
            return "index";
        }
    };

    @Override
    public ReactNativeHost getReactNativeHost() {
        return mReactNativeHost;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        SoLoader.init(this, false);
    }
}

4. 在React Native中调用

在React Native组件中,导入NativeModulesDeviceEventEmitter,并调用定义的方法。

import React, { Component } from 'react';
import { View, Text, StyleSheet, NativeModules, DeviceEventEmitter } from 'react-native';

export default class App extends Component {
  constructor() {
    super();
    this.state = {
      name: 'To get started, edit App.js',
      sendEvent: 'Send Event'
    };
  }

  toast = () => {
    let obj = {
      id: 1,
      name: "xiaohong"
    };
    NativeModules.TestModules.Toasts(obj);
  };

  toastFinishCallback = () => {
    NativeModules.TestModules.ToastFinished("调用了原生并带有回调", (result) => {
      this.setState({
        name: result.name
      });
    });
  };

  sendEvent = () => {
    NativeModules.TestModules.sendEvent();
  };

  componentWillMount() {
    DeviceEventEmitter.addListener('sendEvent', (e) => {
      this.setState({
        sendEvent: e.name
      });
    });
  };

  startActivity = () => {
    NativeModules.TestModules.startActivity();
  };

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome} onPress={this.toast}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions} onPress={this.toastFinishCallback}>
          {this.state.name}
        </Text>
        <Text style={styles.instructions} onPress={this.sendEvent}>
          {this.state.sendEvent}
        </Text>
        <Text style={styles.instructions} onPress={this.startActivity}>
          点击开启activity
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

通过以上步骤,你可以实现Android原生模块向React Native回传参数,包括使用Callback和RCTDeviceEventEmitter方式,并能够启动原生Activity。这种方式增强了React Native与原生平台的交互能力,适用于复杂的移动应用开发场景。

0 Answers