?前提是用react-native init 工程名 已經初始化好一個可以正常運行的RN工程(檢驗標準是在手機上可以正常運行)。
下面的步驟是在RN0.17版本的,0.18版本后也是可以的,由于官方進一步封裝,具體步驟可能略有不同。
一、導入Android原生模塊的步驟
步驟1.新建java類繼承ReactContextBaseJavaModule.
public class MyToastModule extends ReactContextBaseJavaModule
必須復寫getName方法,return后跟的是JS里要調用的名字(可不同于類名)。
public String getName() {
return "MyToastAndroid";
}
定義要被JS使用的方法,要加上注解@ReactMethod
@ReactMethod
public void show(){
Toast.makeText(getReactApplicationContext(),"hello",Toast.LENGTH_LONG).show();
}
步驟2.新建類實現ReactPackage接口
public class MyReactPackage? implements ReactPackage
有三個方法需要實現:createNativeModeule,createJSModules,createViewManagers.這三個方法都返回list,
要注意一點是雖然默認返回null,但這樣寫編譯時會出錯,要改寫成返回空集合,一般寫成
return Collections.emptyList();
此時需要在createNativeModeule里,返回帶有上面module的集合
@Override
public List createNativeModules(ReactApplicationContext reactContext) {
return Arrays.asList(
new MyToastModule(reactContext)
);
}
步驟3.在MainActivity里(在RN工程里是自動生成的入口activity),添加上面的自定義的ReactPackage
mReactInstanceManager = ReactInstanceManager.builder()
。。。。//省略其他代碼
.addPackage(new MainReactPackage())
.addPackage(new MyReactPackage())
。。。。//省略其他代碼
步驟4.在JS里調用剛才的原生模塊
React.NativeModules.MyToastAndroid.show();
二、上面是最簡單的一種調用,基本步驟是不變的,接下來是在上面基礎上多了點東西的調用。
1.在JS里調用帶參數的原生模塊里的方法
將上面的MyToastModule類里的show方法改為
@ReactMethod
public void show(String message,int dur){
Toast.makeText(getReactApplicationContext(),message,dur).show();
}
在JS里調用為
React.NativeModules.MyToastAndroid.show("hello",1);
2.在JS里調用原生模塊里的預設參數
在MyToastModule的Java類里復寫方法getConstants,此方法返回了需要導出給JavaScript使用的常量
@Override? ? ? ? public Map getConstants() {? ? final Map constants = new HashMap<>();? ? ? ? ? ? constants.put("HAHA", Toast.LENGTH_SHORT);? ? ? ? ? ? constants.put("LONG", Toast.LENGTH_LONG);
return constants;? ? ? ? }
在JS里調用為
React.NativeModules.MyToastAndroid.show("hellohaha",React.NativeModules.MyToastAndroid.HAHA);
3.將原生模塊封裝成一個JS模塊,以便省下每次都從NativeModules中獲取對應模塊的步驟,從JS端訪問更為方便。
新建名為MyToastAndroidJS的JS文件,文件里內容為
'use strict'
var {NativeModules} = require('react-native');
module.exports=NativeModules.MyToastAndroid;
在其他JS代碼或文件中可以這樣調用,
var MyToastAndroidLOL = require('./MyToastAndroidJS');//此處確保按文件路徑可以被查找到
MyToastAndroidLOL.show('haha JSModule',MyToastAndroidLOL.HAHA);
三、回調函數
上面全是JS調用原生模塊里的方法,有參或無參,但原生模塊只是被調用,沒有反饋回來數據,下面是回調使用說明。(此處承接上面的3)
1.使用Callback回調
在MyToastAndroid中添加方法showAll。在showAll的參數中的callback是com.facebook.react.bridge.Callback,注意別導錯包了。
@ReactMethod
public void showAll(int a,int b,Callback erroCallBack,Callback successCallback){
try{
int c=a/b;
successCallback.invoke(a,b);
}catch(Exception e){
erroCallBack.invoke(e.getMessage());
}
}
在JS中調用showAll方法
MyToastAndroidJJ.showAll(
1,2,
(msg) => {console.log(msg)},
(x,y) => {console.log(x+':'+y)}
);
運行后logcat上會打印出1:2,
當是
MyToastAndroidJJ.showAll(
1,0,
(msg) => {console.log(msg)},
(x,y) => {console.log(x+':'+y)}
);
運行后logcat上會打印出 divide by zero等異常信息。
這樣就實現了原生模塊向JS傳遞數據,并且其中有很大的自由度供調用實現。但要注意showAll里的參數個數在被JS調用時是要一一對應的,在MyToastAndroid中定義了幾個參數就要在JS中調用時提供幾個參數。
2.使用Promise回調
在MyToastAndroid中添加方法showB
@ReactMethod
public void showB(int a,int b,Promise promise){
try{
int c=a/b;
promise.resolve(a+b);
}catch(Exception e){
promise.reject("test:"+e.getMessage());
}
}
在JS中,聲明一個方法
showBInJS: async function (){
try{
var c = await MyToastAndroidJJ.showB(1,2);
console.log("test:"+c);
}catch(e){
console.log(e);
}
},
在JS中調用
this.showBInJS();
在log中會打印出 test:3。
把上面聲明中的2改為0,保存然后Reload JS。
在log中會打印出 test:divide by zero 等異常信息。
上面是返回一個參數,下面是可以返回多個參數的方式(不唯一)
在MyToastAndroid中改寫方法showB
@ReactMethod
public void showB(int a,int b,Promise promise){
try{
int c=a/b;
WritableMap map = Arguments.createMap();
map.putInt("haha",a);
map.putInt("hehe",b);
promise.resolve(map);
}catch(Exception e){
promise.reject("fyp:"+e.getMessage());
}
}
在JS中改寫showBInJS的聲明
showBInJS: async function (){
try{
var {haha,hehe} = await MyToastAndroidJJ.showB(1,2);
console.log("test:"+haha+":"+hehe);
}catch(e){
console.log(e);
}
},
調用不變。
重新react-native run-android,在log里會打印出 test:1:2。