原生模块简介
有时候一个 React Native 应用需要访问原生平台的 API,比如相机,但默认情况下 JavaScript 无法直接调用这些原生 API。原生模块系统通过将 Java 类的实例暴露给 JavaScript,允许开发者在 JS 代码中执行特定的原生代码。
简单来说,桥接原生主要用于实现 React 层中 JavaScript 无法完成的需求,例如:
- 复杂、高性能组件:如复杂表格、视频播放器等;
- 原生层开发能力:如传感器编程、widget 等;
- 平台属性:如系统信息、设备信息等;
- 对接三方应用:如相机、相册、地图等。
桥接原生方法
编写并注册原生层方法
-
使用 Android Studio 打开项目,找到
android > app > src > main > java > com.rndemo(RN 应用的项目名称)>MainApplication.java。定位到getPackages方法,该方法返回 React Native 桥接的各种包,初始时未添加任何自定义包。 -
在
com.rndemo包下新建rn文件夹,并在其中创建RnDemoPackage.java类。该类需要实现ReactPackage接口,并重写createNativeModules和createViewManagers两个方法。createNativeModules用于导入 RN 原生模块,createViewManagers用于导入 RN 原生组件。 -
createNativeModules方法返回一个原生模块(NativeModule)的集合,因此需要先创建一个原生模块,例如命名为AppModule.java。该类需继承ReactContextBaseJavaModule并重写getName方法。同时,AppModule需要一个构造函数,可以通过快捷键Alt + Insert选择 Constructor,并在弹出的窗口中选择第二个带参数的构造函数。 -
若
AppModule需要向 JavaScript 暴露一个打开手机相册的方法,可以添加openGallery方法,并使用@ReactMethod注解修饰。该方法中使用的DeviceUtil工具类需提前准备,位于rn同级目录下的utils文件夹中。
最终 AppModule 的代码如下:
package com.rndemo.rn;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.rndemo.utils.DeviceUtil;
public class AppModule extends ReactContextBaseJavaModule {
public AppModule(@Nullable ReactApplicationContext reactContext) {
super(reactContext);
}
@NonNull
@Override
public String getName() {
// 返回原生模块注册时的名称,JS 层调用时需要知道此名称
return "CustomApp";
}
@ReactMethod
public void openGallery() {
if (getCurrentActivity() == null) {
return;
}
DeviceUtil.openGallery(getCurrentActivity());
}
}
-
回到
RnDemoPackage类,在createNativeModules方法中将注册好的AppModule添加到模块集合中。 -
最后,在
MainApplication.java的getPackages方法中注册RnDemoPackage。
JS 层调用原生方法
在 JavaScript 层,可以从 NativeModules 中取出注册好的原生模块并调用其方法。示例代码如下:
import React from 'react';
import {StyleSheet, View, Button, NativeModules} from 'react-native';
export default () => {
return (
<View style={styles.root}>
<Button
title="桥接原生方法"
onPress={() => {
const {CustomApp} = NativeModules;
CustomApp?.openGallery();
}}
/>
</View>
);
};
const styles = StyleSheet.create({
root: {
width: '100%',
height: '100%',
},
});
点击按钮即可调用原生方法打开相册。
原生模块暴露带返回值的方法
需要注意的是,从 JS 层调用原生方法是一个异步过程,因此原生层中带返回值的方法不能直接返回,而需要使用 Promise 实现。例如,原生层可以提供一个返回应用版本名称的方法 getVersionName,JS 层通过 Promise 获取返回值。
桥接原生常量
编写并注册原生常量方法
在 AppModule 原生组件中重写 getConstants 方法,以暴露常量给 JavaScript。
JS 层获取原生常量(同步获取)
在 JS 层可以直接同步读取原生模块暴露的常量,无需异步调用。示例中展示了如何获取并显示常量值。