Android 原生模块
原生模块和原生组件是我们传统架构中使用的稳定技术。 当新架构稳定后,它们将被弃用。新架构使用TurboModule和Fabric 组件来实现类似的功能。
有时候 App 需要访问平台 API,但 React Native 可能还没有相应的模块包装;或者你需要复用一些 Java 代码,而不是用 Javascript 重新实现一遍;又或者你需要实现某些高性能的、多线程的代码,譬如图片处理、数据库、或者各种高级扩展等等。
我们把 React Native 设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不认为它应当在日常开发的过程中经常出现,但具备这样的能力是很重要的。如果 React Native 还不支持某个你需要的原生特性,你应当可以自己实现该特性的封装。
Native Module Setup
Native modules are usually distributed as npm packages, apart from the typical javascript files and resources they will contain an Android library project. This project is, from NPM's perspective just like any other media asset, meaning there isn't anything special about it from this point of view. To get the basic scaffolding make sure to read Native Modules Setup guide first.
开启 Gradle Daemon
我们建议开启Gradle Daemon来加速 Java 代码编译。
Toast 模块
本向导会用Toast作为例子。假设我们希望可以从 Javascript 发起一个 Toast 消息(一种会在屏幕下方弹出、保持一段时间的消息通知)。
我们首先来创建一个原生模块。一个原生模块是一个继承了ReactContextBaseJavaModule
的 Java 类,它可以实现一些 JavaScript 所需的功能。我们这里的目标是可以在 JavaScript 里写ToastExample.show('Awesome', ToastExample.SHORT);
,来调起一个短暂的 Toast 通知。
创建一个新的 Java 类并命名为ToastModule.java
,放置到android/app/src/main/java/com/your-app-name/
目录下,其具体代码如下:
// ToastModule.java
package com.your-app-name;
import android.widget.Toast;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;
public class ToastModule extends ReactContextBaseJavaModule {
private static ReactApplicationContext reactContext;
private static final String DURATION_SHORT_KEY = "SHORT";
private static final String DURATION_LONG_KEY = "LONG";
public ToastModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}
}
ReactContextBaseJavaModule
要求派生类实现getName
方法。这个函数用于返回一个字符串名字,这个名字在 JavaScript 端标记这个模块。这里我们把这个模块叫做ToastExample
,这样就可以在 JavaScript 中通过NativeModules.ToastExample
访问到这个模块。译注:RN 已经内置了一个名为 ToastAndroid 的模块,所以在练习时请勿使用 ToastAndroid 的名 字,否则运行时会报错名字冲突!
@Override
public String getName() {
return "ToastExample";
}
一个可选的方法getContants
返回了需要导出给 JavaScript 使用的常量。它并不一定需要实现,但在定义一些可以被 JavaScript 同步访问到的预定义的值时非常有用。
@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 方法需要使用注解@ReactMethod
。方法的返回类型必须为void
。React Native 的跨语言访问是异步进行的,所以想要给 JavaScript 返回一个值的唯一办法是使用回调函数或者发送事件(参见下文的描述)。
@ReactMethod
public void show(String message, int duration) {
Toast.makeText(getReactApplicationContext(), message, duration).show();
}
参数类型
下面的参数类型在@ReactMethod
注明的方法中,会被直接映射到它们对应的 JavaScript 类型。
Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array