React-native调用Android原生模块

于恺
2023-12-01

准备工作:具体详情参考React-Native官方文档

IDE: WebStorm 和Android Studio(webstorm不支持java高亮,所以用AS辅助下)

demo放到github上了,有需要的可以参考一下.  下载demo

1.为什么调用原生的一些东西? 

   有时候应用程序需要访问平台API,React Native目前还没有相应的模块。也许你想重用一些现有的Java代码,而不必用JavaScript重新实现它,或者编写一些高性能,多线程的代码,例如图像处理,数据库或任何数量的高级扩展。

我们设计了React Native,因此您可以编写真实的本机代码并访问平台的全部功能。这是一个更高级的功能,我们不希望它成为通常开发过程的一部分,但它存在必不可少。如果React Native不支持您需要的本机功能,您应该能够自己构建它。

2.创建个Toast模块做为示例:

 

我们首先创建一个本地模块。本地模块是一个Java类,通常扩展ReactContextBaseJavaModule该类并实现JavaScript所需的功能。我们的目标是能够使用ToastExample.show('Awesome', ToastExample.SHORT);JavaScript 编写在屏幕上显示简短toast。

2.1:创建一个名为ToastModule.java,其内容如下:

 

import android.widget.Toast;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

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

import javax.annotation.Nullable;

/**
 * Description:
 * Created by song on 2018/7/3.
 * email:bjay20080613@qq.com
 */
public class ToastModule  extends ReactContextBaseJavaModule {
    private static final String DURATION_SHORT_KEY="SHORT";
    private static final String DURATION_LONG_KEY="LONG";
    public ToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

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

    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        final Map<String,Object> constants=new HashMap<>();
        constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
        constants.put(DURATION_LONG_KEY,Toast.LENGTH_LONG);
        return constants;
    }

    @ReactMethod
    public void show(String message,int duration){
        Toast.makeText(getReactApplicationContext(),message,duration).show();
    }

ReactContextBaseJavaModule要求实现一个被调用的方法getName。此方法的目的是NativeModule在JavaScript中返回表示该类的字符串名称。所以在这里我们将调用它,ToastExample以便我们可以通过React.NativeModules.ToastExampleJavaScript 访问它。

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

一个可选的方法调用getConstants返回暴露给JavaScript的常量值。它的实现不是必需的,但对于需要同步从JavaScript到Java进行通信的关键预定义值非常有用。

  @Override
  public Map<String, Object> getConstants() {
    final Map<String, Object> constants = new HashMap<>();
    constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
    constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
    return constants;
  }

要向JavaScript公开方法,必须使用Java方法注释Java方法@ReactMethod。桥接方法的返回类型总是如此void。React Native桥是异步的,因此将结果传递给JavaScript的唯一方法是使用回调或发射事件(请参见下文)。

  @ReactMethod
  public void show(String message, int duration) {
    Toast.makeText(getReactApplicationContext(), message, duration).show();
  }

 

3.注册模块

Java中的最后一步是注册模块; 这发生在createNativeModules你的应用程序包中。如果模块未注册,则无法从JavaScript获得。

创建一个名为CustomToastPackage.javainside android/app/src/main/java/com/your-app-name/folder 的新Java类,其内容如下:

 
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;

/**
 * Description:
 * Created by song on 2018/7/3.
 * email:bjay20080613@qq.com
 */
public class CustomToastPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules=new ArrayList<>();
        modules.add(new ToastModule(reactContext));
        return modules;
    }

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

该包需要getPackagesMainApplication.java文件的方法中提供。该文件存在于react-native应用程序目录中的android文件夹下。该文件的路径是:android/app/src/main/java/com/your-app-name/MainApplication.java

 

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

4.把原生模块包装到js模块中:

在react-native工程下,创建一个js文件;

文件中添加:

 

import {NativeModules} from 'react-native';
module.exports = NativeModules.ToastExample;

5.在App.js中调用原生模块:

 

//从android.js中导入
import ToastExample from './android';

const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' +
    'Cmd+D or shake for dev menu',
  android: 'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
});

type Props = {};
export default class App extends Component<Props> {
  render() {
    return (
      <View style={styles.container}>
        //调用
        <Text style={styles.welcome} onPress={()=>ToastExample.show("js中点的啊",ToastExample.SHORT)}>
         调用原生Toast!
        </Text>
      </View>
    );
  }

}
 类似资料: