React-Native 与原生层之间的通信
2018-05-14 本文已影响84人
e8f86562b6f2
写在前面:在你编写react-native应用的时候,有些时候是需要原生层的api来完成特定功能的;举个栗子:调起拨打电话界面,蓝牙通信,wifi协议等等;所以RN与原生代码通讯对于混合编程是至关重要的。
为了实现JS与Native之间的通信,facebook也提供了三种通信方式。分别是:
1. EventEmitter消息机制:由Native发起,可以任意时刻传递到JS;
2. Callback回调方式:由JS调用,原生代码响应方返回;
3. Promise机制方式:由JS调用,只是每次使用都需要调用;
1.JS与IOS原生通信:
RnModule.h 文件
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
// 继承自RCTEventEmitter
@interface RnModule : RCTEventEmitter<RCTBridgeModule>
@end
RnModule.m 文件
#import "RnModule.h"
@implementation RnModule
///此名供JS调用,一旦声明,该类的实例已经创建好了
RCT_EXPORT_MODULE(rn);
- (NSArray<NSString *> *)supportedEvents
{
return @[@"ar"];
}
/** 注意:ios 更新ui只能再主线程更新 **/
///native 向 js 发送
RCT_EXPORT_METHOD(event:(NSString *)query){
///这里可以进行一系列原生操作
[self sendEventWithName:@"ar" body:@{@"message":@"native--》rn",@"data":query}];
};
///Callback方式,异步返回
RCT_EXPORT_METHOD(eventCallback:(RCTResponseSenderBlock)callback){
///这里可以进行一系列原生操作
NSString *msg = @"我是==>>Callback回调";
callback(@[msg]);
};
///Promise,异步返回
RCT_REMAP_METHOD(eventPromise,
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject){
///这里可以进行一系列原生操作
NSString *msg = @"我是==>>Promise回调";
resolve(msg);
};
@end
2.JS与Andoird原生通信:
CustomPackage.java文件
package com.demo.JSModule;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CustomPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new RnModule(reactContext));
return modules;
}
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
RnModule.java文件
package com.demo.JSModule;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
public class RnModule extends ReactContextBaseJavaModule {
public static final String RN_NAME = "rn";
private ReactApplicationContext mContext;
public RnModule(ReactApplicationContext reactContext) {
super(reactContext);
mContext = reactContext;
}
/**
* 此名供JS调用,不设置将不曝露给js,会报错
*/
public String getName() {
return RN_NAME;
}
/**
* 用@ReactMethod 注解标注:表明该方法会被JS调用。
* native 向 js 发送
*/
@ReactMethod
public void event(String query) {
//做一系列原生操作
executeResult("ar", "native--》rn", query);
}
/**
* Callback方式,异步返回
*/
@ReactMethod
public void eventCallback(Callback Callback) {
//做一系列原生操作
String msg = "我是==>>Callback回调";
Callback.invoke(msg);
}
/**
* Promise,异步返回
*/
@ReactMethod
public void eventPromise(Promise Promise) {
//做一系列原生操作
String msg = "我是==>>Promise回调";
Promise.resolve(msg);
}
/**
* native 向 js 发送 函数
*/
private void executeResult(String methodName, String message, String data) {
WritableMap writableMap = new WritableNativeMap();
writableMap.putString("message", message);
writableMap.putString("data", data);
mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(methodName, writableMap);
}
}
然后再MainApplication.java中添加
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
+ new CustomPackage()
);
}
3.js代码
/**
*@ time: 2018/3/28
*@ author: 二 白
*@ use:
*/
import React, {Component} from 'react';
import {
View,
DeviceEventEmitter,
NativeModules,
Text,
NativeEventEmitter
} from 'react-native';
import {Button, Toast} from 'teaset';
export default class Test1 extends Component {
constructor(props) {
super(props);
this.state = {
value: '',
message: ''
};
}
componentWillMount() {
if (iOS) {
// 拿到原生模块
const {rn} = NativeModules;
// 创建自定义事件接口
const iosManagerEmitter = new NativeEventEmitter(rn);
this.iosListener = iosManagerEmitter.addListener("ar", (msg) => {
this.setState({
value: msg.data,
message: msg.message
});
});
}
else {
this.androidListener = DeviceEventEmitter.addListener('ar', (msg) => {
this.setState({
value: msg.data,
message: msg.message
});
});
}
}
componentWillUnmount() {
//组件卸载的是否需要移除监听
if (iOS) this.iosListener && this.iosListener.remove();
else this.androidListener && this.androidListener.remove();
}
AN2RN = (e) => {
if (e === 1) {
NativeModules.rn.event('我来了!');
}
else if (e === 2) {
NativeModules.rn.eventCallback((callback) => {
Toast.info(callback);
});
}
else {
NativeModules.rn.eventPromise().then((promise) => {
Toast.info(promise);
});
}
};
// 等待Promise对象返回后才执行,在某一些业务上很重要
async es() {
const info = await NativeModules.rn.eventPromise();
Toast.info(info);
};
render() {
const {value, message} = this.state;
return (
<View style={{
flex: 1,
backgroundColor: '#FFFFFF'
}}>
<View style={{marginTop: px2dp(200), marginHorizontal: px2dp(100)}}>
<Button onPress={() => {
this.AN2RN(1)
}} type='secondary' size='lg' title='native主导,任意时刻触发1'/>
</View>
<View style={{marginTop: px2dp(80), marginHorizontal: px2dp(100)}}>
<Button onPress={() => {
this.AN2RN(2)
}} type='secondary' size='lg' title='callback方式fuck'/>
</View>
<View style={{marginTop: px2dp(80), marginHorizontal: px2dp(100)}}>
<Button
onPress={() => {
this.AN2RN(3)
}} type='secondary' size='lg' title='Promise方式'/>
</View>
<View style={{marginTop: px2dp(80), marginHorizontal: px2dp(100)}}>
<Button
onPress={this.es} type='secondary' size='lg' title='Promise(async/await)'/>
</View>
<View style={{marginTop: px2dp(20), marginHorizontal: px2dp(100)}}>
{
value ? <Text style={{fontSize: FONT_SIZE(20)}}>
data:{value},
message:{message}
</Text>
: null
}
</View>
</View>
);
}
}
注意:
1.需要注意的地方都在代码中注释了;
2.js代码写法上在不同的平台上有一点小差异,需要区分出来;
3.这里只是用代码简单描述了一下,可以把本项目clone下来,看具体运行效果;
4.复杂的业务还是需要原生的知识,如果没有时间去学习原生知识的话,社区有封装好的相关组件,只需了解其API,js调用即可;