前言
React Native一經(jīng)推出就非常火爆,吸引了國內(nèi)外的開發(fā)者的注意,好處不必多說,該文章以筆記的形式來記錄自己的學(xué)習(xí)歷程。
本文記錄了基于官方文檔來創(chuàng)建一個(gè)Android平臺(tái)的自定義的原生模塊(NativeModule)。
準(zhǔn)備
需要提前準(zhǔn)備好一個(gè)ReactNative項(xiàng)目,同時(shí)App與服務(wù)器端鏈接良好,可以正常"Reload JS"
關(guān)于本例
本例代碼將實(shí)現(xiàn)一個(gè)Toast的Native(React官方已提供該模塊),借此來學(xué)習(xí)創(chuàng)建一個(gè)自定義NativeModule(原生組件)的方法。
效果圖如下:
編寫模塊
首先編寫一個(gè)自定義模塊的類,該類需要繼承ReactContextBaseJavaModule
, 并需要實(shí)現(xiàn)getName()
方法返回一個(gè)模塊名稱,在本實(shí)例中,該自定義模塊將實(shí)現(xiàn)Android的Toast功能,所以定義了一個(gè)show()方法,并加上了ReactMethod
注解,這個(gè)注解可以將show(String msg, int duration)
中的Java參數(shù)類型映射成Js中對應(yīng)的數(shù)據(jù)類型,具體映射關(guān)系如下:
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";
}
/**
* 可以設(shè)置一些常量,能夠在js層調(diào)用,本例中在JS代碼中調(diào)用如"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)是需要注冊才能生效的,所以編寫好模塊之后需要重新打包安裝到手機(jī)上。
編寫Package
注冊模塊首先可以先寫個(gè)自定義的Package,顧名思義,就是一個(gè)可以包含你自己寫的模塊的一個(gè)包,然后把包在MainActivity
(本例中的類)中注冊下,通過已有工程引入React組件的可以根據(jù)實(shí)際情況修改,也不難。
本例中新建一個(gè)MyPackage
類,通過實(shí)現(xiàn)ReactPackage的三個(gè)接口來完成模塊的綁定,其中createNativeModules
方法是我們本例需要用到的,其他兩個(gè)之后再說,要注意三個(gè)方法均不能返回null類型,不需要用到的請傳入一個(gè)空集合!
源代碼
public class MyPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>(1);
// 將我們自定義模塊添加一個(gè)集合中,這樣React組件就會(huì)在合適的時(shí)機(jī)將我們引用的模塊加載進(jìn)去,這樣后面才能愉快地玩耍~
modules.add(new ToastAndroidModule(reactContext));
return modules;
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
//現(xiàn)在不需要用到,不要傳null,否則報(bào)錯(cuò)
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
//現(xiàn)在不需要用到,不要傳null,否則報(bào)錯(cuò)
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()
);
}
}
編譯打包&安裝到手機(jī)
由于我們修改了Android代碼,因此需要重新編譯打包,并安裝到我們的手機(jī)中,此步驟省略。
編寫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);