當(dāng)有時(shí)候RN項(xiàng)目需要訪問原生的api但是rn官方并還沒封裝這個(gè)模塊時(shí)变姨,就需要使用自己去手動(dòng)封裝墓臭。調(diào)用Android原生代碼,以最簡(jiǎn)單的彈Toast為例:
-
定義ReactContextBaseJavaModule模塊
- 首先在android的目錄下定義一個(gè)類去繼承ReactContextBaseJavaModule類,實(shí)現(xiàn)getName方法采郎。此方法返回的參數(shù)就是你使用js調(diào)用的模塊名粟誓。
- 根據(jù)自己的需求選擇是否去重寫getConstants方法枷邪,這個(gè)方法的作用是給js提供一些常量使用隙畜,通過map的鍵值去存儲(chǔ),map的鍵是js調(diào)用的名稱抖部,key是對(duì)應(yīng)的值。
- 然后就是定義你對(duì)js提供的方法议惰,對(duì)js提供的方法必須是沒有返回值的慎颗,如果需要有返回值的話,則需要增加Callback參數(shù)言询,js通過callback獲取函數(shù)需要返回的值俯萎。需要注意的是必須在方法上面加上@ReactMethod注解,才能讓js識(shí)別調(diào)用运杭。具體代碼如下:
/**
* 原生模塊
*/
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);
}
/**
*
* @return js調(diào)用的模塊名
*/
@Override
public String getName() {
return "ToastModule";
}
/**
* 給rn定義模塊的一些常量
* @return 常量的一些鍵值
*/
@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注解夫啊,使這個(gè)方法被js調(diào)用
* @param message 文本
* @param duration 時(shí)長(zhǎng)
*/
@ReactMethod
public void show(String message, int duration, Callback success,Callback error) {
try {
Toast.makeText(getReactApplicationContext(), message, duration).show();
success.invoke("success");
}
catch (Exception e){
error.invoke("error");
}
}
}
- 定義好模塊之后,接下來就需要去注冊(cè)模塊辆憔。非常簡(jiǎn)單撇眯,定義一個(gè)類去實(shí)現(xiàn),ReactPackage接口报嵌。這個(gè)接口只有兩個(gè)方法,createViewManagers他是注冊(cè)需要被調(diào)用原生控件的(下篇文章會(huì)講到)熊榛,createNativeModules就是注冊(cè)原生方法需要實(shí)現(xiàn)的锚国,他的返回值是個(gè)list,創(chuàng)建一個(gè)list然后把你之前定義的ReactContextBaseJavaModule添加進(jìn)去就好玄坦。代碼如下血筑。
public class ToastReactPackage implements ReactPackage {
/**
*
* @param reactContext 上下文
* @return 需要調(diào)用的原生控件
*/
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
/**
*
* @param reactContext 上下文
* @return 需要調(diào)用的原生模塊
*/
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ToastModule(reactContext));
return modules;
}
}
- 把上一步定義好的ReactPackage模塊在application下注冊(cè)。原生這邊所有的工作就已經(jīng)結(jié)束煎楣。
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new ToastReactPackage()//新添加需要注冊(cè)的模塊
);
}
};
- 原生端工作已完成豺总。接下來就是js端,只需要加載NativeModules模塊转质,
從NativeModules中獲取之前定義的ReactContextBaseJavaModule對(duì)應(yīng)的getName的值就可以調(diào)用對(duì)應(yīng)的方法了园欣,具體如下:
import React, {Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
NativeModules
} from 'react-native';
export default class RNDemo extends Component {
_toast(){
NativeModules.ToastModule.show('toast', NativeModules.ToastModule.SHORT,(success)=>{alert(success)},(error)=>{alert(error)})
}
render() {
return (
<View style={styles.container}>
<Text onPress={this._toast} style={styles.welcome}>
Welcome to React Native!
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('RNDemo', () => RNDemo);