准备工作:具体详情参考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.ToastExample
JavaScript 访问它。
@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.java
inside 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();
}
}
该包需要getPackages
在MainApplication.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>
);
}
}