前言
React Native一经推出就非常火爆,吸引了国内外的开发者的注意,好处不必多说,该文章以笔记的形式来记录自己的学习历程。
本文记录了基于官方文档来创建一个Android平台的自定义的原生模块(NativeModule)。
准备
需要提前准备好一个ReactNative项目,同时App与服务器端链接良好,可以正常"Reload JS"
关于本例
本例代码将实现一个Toast的Native(React官方已提供该模块),借此来学习创建一个自定义NativeModule(原生组件)的方法。
效果图如下:
编写模块
首先编写一个自定义模块的类,该类需要继承ReactContextBaseJavaModule
, 并需要实现getName()
方法返回一个模块名称,在本实例中,该自定义模块将实现Android的Toast功能,所以定义了一个show()方法,并加上了ReactMethod
注解,这个注解可以将show(String msg, int duration)
中的Java参数类型映射成Js中对应的数据类型,具体映射关系如下:
Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array
代码本身很简单,具体可以看注释
源代码
public class ToastAndroidModule extends ReactContextBaseJavaModule {
private static final String DURATION_SHORT_KEY = "SHORT";
private static final String DURATION_LONG_KEY = "LONG";
public ToastAndroidModule(ReactApplicationContext reactContext) {
super(reactContext);
}
/**
* 定义模块名称
* @return
*/
@Override
public String getName() {
return "MyToastAndroid";
}
/**
* 可以设置一些常量,能够在js层调用,本例中在JS代码中调用如"MyToastAndroid.LONG"
* @return
*/
@Nullable
@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>(2);
constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
return constants;
}
/**
* 自定义方法,通过ReactMethod注解可以把一些Java常量类型映射成js类型
* @param msg
* @param duration
*/
@ReactMethod
public void show(String msg, int duration) {
Toast.makeText(getReactApplicationContext(), msg, duration).show();
}
}
注册模块
在目前0.20版本上,我们自定义原生模块(NativeModule)是需要注册才能生效的,所以编写好模块之后需要重新打包安装到手机上。
编写Package
注册模块首先可以先写个自定义的Package,顾名思义,就是一个可以包含你自己写的模块的一个包,然后把包在MainActivity
(本例中的类)中注册下,通过已有工程引入React组件的可以根据实际情况修改,也不难。
本例中新建一个MyPackage
类,通过实现ReactPackage的三个接口来完成模块的绑定,其中createNativeModules
方法是我们本例需要用到的,其他两个之后再说,要注意三个方法均不能返回null类型,不需要用到的请传入一个空集合!
源代码
public class MyPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>(1);
// 将我们自定义模块添加一个集合中,这样React组件就会在合适的时机将我们引用的模块加载进去,这样后面才能愉快地玩耍~
modules.add(new ToastAndroidModule(reactContext));
return modules;
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
//现在不需要用到,不要传null,否则报错
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
//现在不需要用到,不要传null,否则报错
return Collections.emptyList();
}
}
注册Package
写好Package之后,就可以愉快将Package加入到MainActivity
(本例)类里,方法很简单,直接贴部分源代码
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 "AwesomeProject";
}
/**
* Returns whether dev mode should be enabled.
* This enables e.g. the dev menu.
*/
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
//加入我们自己写的Package
new MyPackage()
);
}
}
编译打包&安装到手机
由于我们修改了Android代码,因此需要重新编译打包,并安装到我们的手机中,此步骤省略。
编写JS
JS编写也清晰了然,可以直接查看源码。
源代码
import React, {
AppRegistry,
Component,
StyleSheet,
Text,
View,
NativeModules
} from 'react-native';
class AwesomeProject extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
var MyToastAndroid = NativeModules.MyToastAndroid;
MyToastAndroid.show('This is from MyToastAndroid Native Module', MyToastAndroid.LONG)
}
render() {
return (
<View style={styles.container}>
<Text>
NativeModule Test by BogerChan
</Text>
</View>
);
}
};
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);