1,为什么需要RN与原生互调?

RN会有完成不了的事情,比如打开本地的相机,native接口。跟硬件打交道的话就不行了。

2,首先使用Android studio打开ReactNative项目下的android目录;

我们观察这个项目:它有两个类,MainActivity 和MainApplication;在app.gradle文件中,dependencies(依赖)中,会发现它有一个react-native的依赖包。

3,js调用java,是js先调用c,c在调用java。

4,js调用java流程

RN 如何调用Android 原生组件 reactnative调用原生sdk_RN 如何调用Android 原生组件


RN 如何调用Android 原生组件 reactnative调用原生sdk_java_02


创建ToastExampleMoudle

package com.nativeapp;

import android.widget.Toast;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nullable;
//
public class ToastExampleMoudle extends ReactContextBaseJavaModule {
    private static final String MESSAGE = "MESSAGE";
    public ToastExampleMoudle(ReactApplicationContext reactContext) {
        super(reactContext);
    }
  
    //通过js去弹出一个原生的吐丝
    @ReactMethod//要想这个方法暴露给js必须增加这个注解
    public void show(int duration){
        Toast.makeText(getReactApplicationContext(), "dongnao:" + duration, Toast.LENGTH_SHORT).show();
    }
  
    @Override
    public String getName() {
        return "ToastForAndroid";
    }

    @Override
    public boolean canOverrideExistingModule() {
        return true;
    }
}

创建ExampleReactNativePackage类

package com.nativeapp;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

//注册模块,注册到c
public class ExampleReactNativePackage implements ReactPackage {
//完成注入,需要被js调用java方法
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
    //NativeModule添加到这个集合里,React Native通过这个方法知道当前有多少个需要给js调用的对象
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new ToastExampleMoudle(reactContext));
        return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    //注意这里不能写return null;
        return Collections.emptyList();
    }
}

这是MainActivity

package com.nativeapp;

import com.facebook.react.ReactActivity;

public class MainActivity extends ReactActivity {

    /**
     * Returns the name of the main component registered from JavaScript.
     * This is used to schedule rendering of the component.
     */
     //这里的nativeapp与index.js中的appName名字一样
     //AppRegistry.registerComponent(appName, () => App);
    @Override
    protected String getMainComponentName() {
        return "nativeapp";
    }
}

修改MainApplication

package com.nativeapp;

import android.app.Application;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

import java.util.Arrays;
import java.util.List;
//注册java的模块,提前应用到缓存中心
public class MainApplication extends Application implements ReactApplication {
// reactNative主机
  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(),
          //添加我们定义的ReactPackage
              new ExampleReactNativePackage()
      );
    }
    @Override
    protected String getJSMainModuleName() {
    //指向了程序的入口,index就是rn的主界面
      return "index";
    }
  };
  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

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

看下App.js文件

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import React, {Component} from 'react';
//这里的ToastAndroid,是ToastExampleMoudle类中方法
//     @Override
//     public String getName() {
//         return "ToastForAndroid";
//     }
//     返回的名字。
import {
    Platform,
    StyleSheet,
    ToastAndroid,
    DeviceEventEmitter,
    Text,
    TouchableOpacity,
    View,
    NativeModules
} from 'react-native';

export default class App extends Component<Props> {
     _onPressButton() {
        /*调用ToastExampleMoudle类这个方法
         * @ReactMethod
         * public void show(int duration){
         *   Toast.makeText(getReactApplicationContext(), "dongnao:" + duration, Toast.LENGTH_SHORT).show();
         *   }
         */
         // NativeModules.ToastForAndroid就表示调用ToastExampleMoudle类。
        NativeModules.ToastForAndroid.show(1000);
    }

    
     

    render() {
        return (
            <View style={styles.container}>
                //this._onPressButton.bind(this),调用_onPressButton(),注意这里是es6写法
                <TouchableOpacity onPress={this._onPressButton.bind(this)}>
                    <Text style={styles.hello}>点击了</Text>
                </TouchableOpacity>
   </View>
        );
    }
}

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

我们运行项目,点击文字“点击了”,就会弹出吐丝

5,

RN 如何调用Android 原生组件 reactnative调用原生sdk_facebook_03

ToastExampleMoudle类里面增加如下代码

//1,具有回调参数的
    //2,callback是ReactNative里面的一个接口。这个接口只有一个方法。
    @ReactMethod
    public void testAndroidCallBack(String msg, Callback callback) {
        Toast.makeText(getReactApplicationContext(),msg,Toast.LENGTH_LONG).show();
        //invoke方法的参数是一个可变参数
        callback.invoke("david");
    }

修改app.js类

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import React, {Component} from 'react';
//这里的ToastAndroid,是ToastExampleMoudle类中方法
//     @Override
//     public String getName() {
//         return "ToastForAndroid";
//     }
//     返回的名字。
import {
    Platform,
    StyleSheet,
    ToastAndroid,
    DeviceEventEmitter,
    Text,
    TouchableOpacity,
    View,
    NativeModules
} from 'react-native';

export default class App extends Component<Props> {
    constructor(props) {
        super(props);
        this.state = {
            text: "river",
            text2: "默认",
        }

    }

 
   

    _onPressButton2() {
        NativeModules.ToastForAndroid.testAndroidCallBack("hello David", (result) => {
            this.setState({
                text: result
            })
        });
    }

 
    render() {
        return (
            <View style={styles.container}>
               

                <TouchableOpacity onPress={this._onPressButton2.bind(this)}>
                    <Text style={styles.hello}>{this.state.text}</Text>
                </TouchableOpacity>

            
            </View>
        );
    }
}

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

运行项目,界面出现river文字,点击文字river,文字river变成david;同时弹出吐丝

“hello David”

6,

RN 如何调用Android 原生组件 reactnative调用原生sdk_RN 如何调用Android 原生组件_04


不适用回调方法传递参数,通过promise实现。

在ToastExampleMoudle里添加方法

//最后一个参数是promise
    @ReactMethod
    public void textAndroidPromiseMethod(String msg, Promise promise){
        Toast.makeText(getReactApplicationContext(),msg,Toast.LENGTH_SHORT).show();
        String result = "david";
        //resolve代表正常运行,会走下面的then方法,如果是reject,则会走catch();
        promise.resolve(result);
    }

修改下app.js文件

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import React, {Component} from 'react';
//这里的ToastAndroid,是ToastExampleMoudle类中方法
//     @Override
//     public String getName() {
//         return "ToastForAndroid";
//     }
//     返回的名字。
import {
    Platform,
    StyleSheet,
    ToastAndroid,
    DeviceEventEmitter,
    Text,
    TouchableOpacity,
    View,
    NativeModules
} from 'react-native';

export default class App extends Component<Props> {
    constructor(props) {
        super(props);
        this.state = {
            text: "river",
            text2: "默认",
        }

    }

  
    _onPressButton3() {
        NativeModules.ToastForAndroid.textAndroidPromiseMethod("hello David").then((result) => {
            this.setState({
                text2: result
            })
        })
    }

 

    render() {
        return (
            <View style={styles.container}>
              <TouchableOpacity onPress={this._onPressButton3.bind(this)}>
                    <Text style={styles.hello}>{this.state.text2}</Text>
                </TouchableOpacity>
          </View>
        );
    }
}

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

运行效果,屏幕出现"默认"二字,点击这两个字则默认变为david,同时弹出吐丝"hello david"

7,给js传递一个对象。我们不使用callback,也不使用promise,通过另外一种方式。
完成下面的操作
js作为一个被观察者,想去通知观察者, 比如js有生命周期,我想通知java,生命周期到了一个什么程度。java里面有一方法,但这个方法并不是现在调用,当react某个页面加载的时候,我在通知java这个方法进行调用
我们在ToastExampleMoudle里添加代码

private static final String MESSAGE = "MESSAGE";
   
    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        //让js那边能够使用这些常量
        Map<String,Object> constants = new HashMap<>();
        constants.put(MESSAGE,"动脑 常量");
        return constants;
    }
      @ReactMethod
    public void onScaning() {
        WritableMap params = Arguments.createMap();
        params.putString("key","mydata");
        //通过java的方式发送一个对象事件,java通知js
        getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("EventName", params);
    }

看下App.js文件

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import React, {Component} from 'react';
//这里的ToastAndroid,是ToastExampleMoudle类中方法
//     @Override
//     public String getName() {
//         return "ToastForAndroid";
//     }
//     返回的名字。
import {
    Platform,
    StyleSheet,
    ToastAndroid,
    DeviceEventEmitter,
    Text,
    TouchableOpacity,
    View,
    NativeModules
} from 'react-native';

export default class App extends Component<Props> {
    constructor(props) {
        super(props);
        this.state = {
            text: "river",
            text2: "默认",
        }

    }

    componentDidMount(): void {
        //1,观察者对象     监听java  调用js
        //2,js去监听java
        //3.msg为我接收的数据
        DeviceEventEmitter.addListener("EventName", function (msg) {
            //获取到类里面的成员变量:
            let rest = NativeModules.ToastForAndroid.MESSAGE;
            //这个ToastAndroid是ReactNative自己带的。
            ToastAndroid.show("DeviceEventEmitter收到消息:" + "\n" + rest, ToastAndroid.SHORT)
        })

    }

  

//js作为一个被观察者,想去通知观察者,
// 比如js有生命周期,我想通知java,生命周期到了一个什么程度。
    //java里面有一方法,但这个方法并不是现在调用,当react某个页面
    //加载的时候,我在通知java这个方法进行调用
    _onPressButton4() {

        NativeModules.ToastForAndroid.onScaning();
    }

    render() {
        return (
            <View style={styles.container}>
               <TouchableOpacity onPress={this._onPressButton4.bind(this)}>
                    <Text style={styles.hello}>{this.state.text2}</Text>
                </TouchableOpacity>
            </View>
        );
    }
}

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

我们点击文字,触发_onPressButton4方法,然后会触发android中的onScaning方法;调用onScanning方法的时候执行下面代码会生成一个对象
WritableMap params = Arguments.createMap(); params.putString("key","mydata"); 然后,我们通过getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("EventName", params); 发送了一个名字叫EventName的事件,
最终运行效果:我们运行项目,屏幕上出现"默认"文字,点击"默认"弹出:“DeviceEventEmitter收到消息:动脑常量”

8,我把完整的代码贴上:

package com.nativeapp;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

//注册模块,注册到c
public class ExampleReactNativePackage implements ReactPackage {
//完成注入,需要被js调用java方法
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
    //NativeModule添加到这个集合里,React Native通过这个方法知道当前有多少个需要给js调用的对象
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new ToastExampleMoudle(reactContext));
        return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    //注意这里不能写return null;
        return Collections.emptyList();
    }
}
package com.nativeapp;

import com.facebook.react.ReactActivity;

public class MainActivity extends ReactActivity {

    /**
     * Returns the name of the main component registered from JavaScript.
     * This is used to schedule rendering of the component.
     */
    @Override
    protected String getMainComponentName() {
        return "nativeapp";
    }
}
package com.nativeapp;

import android.widget.Toast;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nullable;
//
public class ToastExampleMoudle extends ReactContextBaseJavaModule {
    private static final String MESSAGE = "MESSAGE";
    public ToastExampleMoudle(ReactApplicationContext reactContext) {
        super(reactContext);
    }
    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        //让js那边能够使用这些常量
        Map<String,Object> constants = new HashMap<>();
        constants.put(MESSAGE,"动脑 常量");
        return constants;
    }
    //通过js去弹出一个原生的吐丝
    @ReactMethod//要想这个方法暴露给js必须增加这个注解
    public void show(int duration){
        Toast.makeText(getReactApplicationContext(), "dongnao:" + duration, Toast.LENGTH_SHORT).show();
    }
    //1,具有回调参数的
    //2,callback是ReactNative里面的一个接口。这个接口只有一个方法。
    @ReactMethod
    public void testAndroidCallBack(String msg, Callback callback) {
        Toast.makeText(getReactApplicationContext(),msg,Toast.LENGTH_LONG).show();
        //invoke方法的参数是一个可变参数
        callback.invoke("david");
    }
    //最后一个参数是promise
    @ReactMethod
    public void textAndroidPromiseMethod(String msg, Promise promise){
        Toast.makeText(getReactApplicationContext(),msg,Toast.LENGTH_SHORT).show();
        String result = "david";
        //resolve代表正常运行,会走下面的then方法,如果是reject,则会走catch();
        promise.resolve(result);
    }
    @ReactMethod
    public void onScaning() {
        WritableMap params = Arguments.createMap();
        params.putString("key","mydata");
        //通过java的方式发送一个对象事件,java通知js
        getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("EventName", params);
    }
    @Override
    public String getName() {
        return "ToastForAndroid";
    }

    @Override
    public boolean canOverrideExistingModule() {
        return true;
    }
}
package com.nativeapp;

import android.app.Application;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

import java.util.Arrays;
import java.util.List;
//注册java的模块,提前应用到缓存中心
public class MainApplication extends Application implements ReactApplication {
// reactNative主机
  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(),
          //添加我们定义的ReactPackage
              new ExampleReactNativePackage()
      );
    }
    @Override
    protected String getJSMainModuleName() {
    //指向了程序的入口,index就是rn的主界面
      return "index";
    }
  };
  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
  }
}
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import React, {Component} from 'react';
//这里的ToastAndroid,是ToastExampleMoudle类中方法
//     @Override
//     public String getName() {
//         return "ToastForAndroid";
//     }
//     返回的名字。
import {
    Platform,
    StyleSheet,
    ToastAndroid,
    DeviceEventEmitter,
    Text,
    TouchableOpacity,
    View,
    NativeModules
} from 'react-native';

export default class App extends Component<Props> {
    constructor(props) {
        super(props);
        this.state = {
            text: "river",
            text2: "默认",
        }

    }

    componentDidMount(): void {
        //1,观察者对象     监听java  调用js
        //2,js去监听java
        //3.msg为我接收的数据
        DeviceEventEmitter.addListener("EventName", function (msg) {
            //获取到类里面的成员变量:
            let rest = NativeModules.ToastForAndroid.MESSAGE;
            //这个ToastAndroid是ReactNative自己带的。
            ToastAndroid.show("DeviceEventEmitter收到消息:" + "\n" + rest, ToastAndroid.SHORT)
        })

    }

    _onPressButton() {
        /*调用ToastExampleMoudle类这个方法
         * @ReactMethod
         * public void show(int duration){
         *   Toast.makeText(getReactApplicationContext(), "dongnao:" + duration, Toast.LENGTH_SHORT).show();
         *   }
         */
        NativeModules.ToastForAndroid.show(1000);
    }

    _onPressButton2() {
        NativeModules.ToastForAndroid.testAndroidCallBack("hello David", (result) => {
            this.setState({
                text: result
            })
        });
    }

    _onPressButton3() {
        NativeModules.ToastForAndroid.textAndroidPromiseMethod("hello David").then((result) => {
            this.setState({
                text2: result
            })
        })
    }

//js作为一个被观察者,想去通知观察者,
// 比如js有生命周期,我想通知java,生命周期到了一个什么程度。
    //java里面有一方法,但这个方法并不是现在调用,当react某个页面
    //加载的时候,我在通知java这个方法进行调用
    _onPressButton4() {

        NativeModules.ToastForAndroid.onScaning();
    }

    render() {
        return (
            <View style={styles.container}>
                //this._onPressButton.bind(this),调用_onPressButton(),注意这里是es6写法
                <TouchableOpacity onPress={this._onPressButton.bind(this)}>
                    <Text style={styles.hello}>点击了</Text>
                </TouchableOpacity>

                <TouchableOpacity onPress={this._onPressButton2.bind(this)}>
                    <Text style={styles.hello}>{this.state.text}</Text>
                </TouchableOpacity>

                <TouchableOpacity onPress={this._onPressButton3.bind(this)}>
                    <Text style={styles.hello}>{this.state.text2}</Text>
                </TouchableOpacity>

                <TouchableOpacity onPress={this._onPressButton4.bind(this)}>
                    <Text style={styles.hello}>{this.state.text2}</Text>
                </TouchableOpacity>
            </View>
        );
    }
}

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