react-native android实战:3 与原生模块混合开发

如何使用

封装好java模块供JavaScript调用,比如我们用js实现不了的控件或模块,可以通过java实现并封装,供JavaScript使用。

java模块的封装

java模块新建LogModule类,继承自ReactContextBaseJavaModule,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class LogModule extends ReactContextBaseJavaModule {

private static final String MODULE_NAME= "Log";
//构造函数
public LogModule(ReactApplicationContext reactContext) {
super(reactContext);
}

//字符串是JavaScript调用模块的名字
@Override
public String getName() {
return MODULE_NAME;
}

//暴露给JavaScript端的方法
@ReactMethod
public void d(String tag,String msg)
{
Log.d(tag,msg);
}
}

新建module注册类,实现自ReactPackage,把module注册如package

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MyAppReactPackage implements ReactPackage {


@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {

List<NativeModule> modules = new ArrayList<>();
//add Log模块
modules.add(new LogModule(reactContext));
//add DBlocal模块
modules.add(new DBlocalModule(reactContext));
return modules;
}

@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

注册包,在MainActivity中

1
2
3
4
5
6
7
8
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage()
+ , new VectorIconsPackage()
+ ,new MyAppReactPackage()
);
}

js调用封装的java

我们把需要自定义的java模块,统一管理,放在NativeBrigde.android.js文件

1
2
3
4
5
6
7
8
9
//log模块
var RCTLog = NativeModules.Log;
var Log = {
d: function (tag: string, msg: string): void {
console.log(tag,msg);
RCTLog.d(tag, msg);
},
};
module .exports ={Log,DBlocal};

需要调用的时候

1
2
var {Log,DBlocal} =  require('../AnComponent/NativeBridge');`
Log.d('hehe',"我是打印输出");

js向java传参

下面的参数类型在@ReactMethod注明的方法中,会被直接映射到它们对应的JavaScript类型。

1
2
3
4
5
6
7
8
Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array

java执行结果回传给js

1 回调

java层需要把结果传递给js,答案就是回调,最典型的一个场景就是javascript层调用java层的网络请求方法,java层拿到网络数据后需要将结果返回给javascript层

为了测试我们在已建好的模块新增方法,invoke回调的参数是无类型,无个数限制的

1
2
3
4
@ReactMethod
public void getValue(String key,final Callback callback){
callback.invoke("我是结果");
}

JavaScript中的使用

1
2
3
4
//从本地数据库取值
DBlocal.getValue('test',(result)=>{
Log.d('hehe',result);
});

在android studio控制台可以看到结果

2 事件监听调用

还可以用事件调用JavaScript层,假设调用了java层方法后,我们希望发送一个事件给javascript,在javascript层再次进行打印输出。

java端

1
2
3
4
5
6
7
8
9
10
11
12
@ReactMethod
public void d(String tag,String msg){
Log.d(tag, msg);
//发送事件给javascript层
WritableMap params = Arguments.createMap();
params.putString("TAG",tag);
params.putString("MSG",msg);
getReactApplicationContext()
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("logInConsole", params);//对应的javascript层的事件名为logInConsole,注册该事件即可进行回调

}

而对应的log.js并不需要做什么修改,我们只需要在想获得该事件的地方注册事件即可,比如我们想在主界面接收该事件,则在index.android.js中进行注册。

JavaScript端

1
2
3
4
5
6
7
8
9
componentDidMount:function(){
Log.d("tag","tag");//调用java层log方法,之后就会回调对应的事件(前提是注册了事件)
//直接使用DeviceEventEmitter进行事件注册
DeviceEventEmitter.addListener('logInConsole',(e)=>{
console.log(e);
}); //记得在UnDidMount里卸载事件

},
});

参考文献

Android React Native使用原生模块