React Native与Android通信交互
Android App巧妙集成React Native最详教程
React Native 实现热部署、增量热更新
本篇内容同样和React Native 与 原生App有关,可以说更加深入了两者之间的感情,为培养下一代做出准备:React Native与原生App的通信交互。
Android系统为我们提供了webview来加载网页,为了让webview加载的网页可以与App交互,系统提供了一套机制帮助我们更方便的实现通信。同样为了实现React Native与原生App之间的通信,FB也实现了自己的一套交互机制。
(1)RCTDeviceEventEmitter 事件方式
(2)Callback 回调方式
(3)Promise
(4)直传常量数据(原生向RN)
三种方式各具不同优缺点
1. RCTDeviceEventEmitter
优点:可任意时刻传递,Native主导控制。
2. Callback
优点:JS调用,Native返回。
缺点:CallBack为异步操作,返回时机不确定
3. Promise
优点:JS调用,Native返回。
缺点:每次使用需要JS调用一次
了解了三者的通信方式,怎么能少了代码的描述!我们来看看代码如何实现。大致的实现步骤如下:
(1)定义Module类,继承ReactContextBaseJavaModule
在Module类中,我们定义交互的方法,例如RN调用Native的方法,Native调用RN的方法等。
(2)定义Package类,继承ReactPackage
实现Package的createNativeModules方法,将Module实例添加到集合。
(3)定义Application,继承ReactApplication
实现getPackages方法,将Package实例添加到getPackages下的集合。
4. 直传常量数据(原生向RN)
跨域传值,只能从原生端向RN端传递。RN端可通过 NativeModules.[module名].[参数名] 的方式获取
1.Module类中的核心代码
[java] view plain copy
- /**
- * 在rn代码里面是需要这个名字来调用该类的方法
- * @return
- */
- @Override
- public String getName() {
- return MODULE_NAME;
- }
名称可以自定义,对接时协商好即可。
[java] view plain copy
- /**
- * RN调用Native的方法
- * @param phone
- */
- @ReactMethod
- public void rnCallNative(String phone) {
- // 跳转到打电话界面
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_CALL);
- intent.setData(Uri.parse("tel:" + phone));
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 跳转需要添加flag, 否则报错
- mContext.startActivity(intent);
- }
在module中定义一个方法,并用@ReactMethod 注解标注:表明该方法会被RN调用。即被RN调用的原生方法必须使用@ReactMethod注解标注。
注意:RN层调用Native层进行界面跳转时,需要设置FLAG_ACTIVITY_NEW_TASK标志,否则会出现如下错误:
[java] view plain copy
- /**
- * Native调用RN
- * @param msg
- */
- public void nativeCallRn(String msg) {
- mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
- .emit(EVENT_NAME,msg);
- }
上面代码定义了原生方法,通过在Android层调用RN层。使用ReactContext的getJSModule方法,emit来发送消息。同样,emit的第一个参数要与RN层中addListener方法的第一个参数相同。
2.自定义Package的核心代码
[java] view plain copy
- /**
- * 通信Package类
- * Created by Song on 2017/2/17.
- */
- public class CommPackage implements ReactPackage {
- public CommModule mModule;
- /**
- * 创建Native Module
- * @param reactContext
- * @return
- */
- @Override
- public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
- List<NativeModule> modules = new ArrayList<>();
- mModule = new CommModule(reactContext);
- modules.add(mModule);
- return modules;
- }
- @Override
- public List<Class<? extends JavaScriptModule>> createJSModules() {
- return Collections.emptyList();
- }
- @Override
- public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
- return Collections.emptyList();
- }
- }
在createNativeModules方法中,初始化集合,并将module实例添加进集合,返回集合实例。
3.Application核心代码
[java] view plain copy
- private static final CommPackage mCommPackage = new CommPackage();
[java] view plain copy
- /**
- * 获取 reactPackage
- * @return
- */
- public static CommPackage getReactPackage() {
- return mCommPackage;
- }
在getPackages方法中,将Package实例添加到Arrays中即可完成注册。以上就是Android层核心代码配置,继续来看React Native层核心代码:
1.调用原生代码
[java] view plain copy
- /**
- * 调用原生代码
- */
- skipNativeCall() {
- let phone = '18637070949';
- NativeModules.commModule.rnCallNative(phone);
- }
在React Native层,通过NativeModules调用commModule,继而调用原生方法即可。注意:commModule要与Module类的getNames方法返回的名称对应。
2. 接收原生调用
[java] view plain copy
- /**
- * 接收原生调用
- */
- componentDidMount() {
- DeviceEventEmitter.addListener('nativeCallRn',(msg)=>{
- title = "React Native界面,收到数据:" + msg;
- ToastAndroid.show("发送成功", ToastAndroid.SHORT);
- })
- }
通过DeviceEventEmitter注册监听,类似于Android中的监听事件。第一个参数标识名称,要与Module中emit的Event Name相同。第二个参数即为处理回掉。
3.界面代码
[html] view plain copy
- render() {
- return (
- <View style={styles.container}>
- <Text style={styles.welcome} >
- {title}
- </Text>
- <Text style={styles.welcome} onPress={this.skipNativeCall.bind(this)}>
- 跳转到拨号界面
- </Text>
- <Image source={require('./images/ic.png')} />
- </View>
- );
- }
在Text中注册单击事件,RN层调用原生代码,跳转到拨号界面。
4.Android层调用RN的代码
[java] view plain copy
- /**
- * 向RN发送消息
- * @param v
- */
- public void sendMsgToRN(View v) {
- Log.e("---","sendMsgToRN");
- MainApplication.getReactPackage().mModule.nativeCallRn("hello");
- }
调用Module中定义的nativeCallRn方法,继而出发RN层代码。以上就是通过 RCTDeviceEventEmitter 模式进行通信交互。可以很清晰的看出,交互都是以主动方式为主。
RN中剩下的两种通信方式,存在一个共同的特点:
从RN层调用Native层,Native层处理完成后,回调RN层
直接看代码实现:
(1)Callback
同样还是在Module类中定义交互方法:
[java] view plain copy
- /**
- * Callback 方式
- * rn调用Native,并获取返回值
- * @param msg
- * @param callback
- */
- @ReactMethod
- public void rnCallNativeFromCallback(String msg, Callback callback) {
- // 1.处理业务逻辑...
- String result = "处理结果:" + msg;
- // 2.回调RN,即将处理结果返回给RN
- callback.invoke(result);
- }
RN中定义回调:
[java] view plain copy
- /**
- * Callback 通信方式
- */
- callbackComm(msg) {
- NativeModules.commModule.rnCallNativeFromCallback(msg,(result) => {
- ToastAndroid.show("CallBack收到消息:" + result, ToastAndroid.SHORT);
- })
- }
(2)Promise
Module类中定义交互方法:
[java] view plain copy
- /**
- * Promise 方式
- * @param msg
- * @param promise
- */
- @ReactMethod
- public void rnCallNativeFromPromise(String msg, Promise promise) {
- Log.e("---","adasdasda");
- // 1.处理业务逻辑...
- String result = "处理结果:" + msg;
- // 2.回调RN,即将处理结果返回给RN
- promise.resolve(result);
- }
RN中定义回调:
[java] view plain copy
- /**
- * Promise 通信方式
- */
- promiseComm(msg) {
- NativeModules.commModule.rnCallNativeFromPromise(msg).then(
- (result) =>{
- ToastAndroid.show("Promise收到消息:" + result, ToastAndroid.SHORT)
- }
- ).catch((error) =>{console.log(error)});
- }
布局中触发单击事件:
[html] view plain copy
- <Text style={styles.welcome} onPress={this.skipNativeCall.bind(this)}>
- 跳转到拨号界面
- </Text>
- <Text style={styles.welcome} onPress={this.callbackComm.bind(this,'callback发送啦')}>
- Callback通信方式
- </Text>
- <Text style={styles.welcome} onPress={this.promiseComm.bind(this,'promise发送啦')}>
- Promise通信方式
- </Text>
(3)直传常量数据(原生向RN)
自定义Module类中实现getConstants方法
[java] view plain copy
- @Nullable
- @Override
- public Map<String, Object> getConstants() {
- return super.getConstants();
- }
以上是默认实现,getConstants方法中调用了super.getConstants(),跟踪源码可以看到
[java] view plain copy
- /**
- * @return a map of constants this module exports to JS. Supports JSON types.
- */
- public @Nullable Map<String, Object> getConstants() {
- return null;
- }
从源码注释中可以看出,该方法是返回一个Map类型的常量,导出到JS端(即RN)。支持JSON 类型。所以,我们只需要重写方法,声明Map集合,向其中添加常量后,返回即可。所以就有了如下代码
[java] view plain copy
- @Nullable
- @Override
- public Map<String, Object> getConstants() {
- Map<String,Object> params = new HashMap<>();
- params.put("Constant","我是常量,传递给RN");
- return params;
- }
此时,在RN端,我们可以通过NativeModules来接收即可
[java] view plain copy
- componentWillMount() {
- let result = NativeModules.MyModule.Constant
- }
最终效果:
Android调用React Native:
React Native调用Android:
源码以上传到github,希望大家star,follow支持哦~
源码下载
转载https://blog.csdn.net/u013718120/article/details/55506238
Android App巧妙集成React Native最详教程
React Native 实现热部署、增量热更新
本篇内容同样和React Native 与 原生App有关,可以说更加深入了两者之间的感情,为培养下一代做出准备:React Native与原生App的通信交互。
Android系统为我们提供了webview来加载网页,为了让webview加载的网页可以与App交互,系统提供了一套机制帮助我们更方便的实现通信。同样为了实现React Native与原生App之间的通信,FB也实现了自己的一套交互机制。
(1)RCTDeviceEventEmitter 事件方式
(2)Callback 回调方式
(3)Promise
(4)直传常量数据(原生向RN)
三种方式各具不同优缺点
1. RCTDeviceEventEmitter
优点:可任意时刻传递,Native主导控制。
2. Callback
优点:JS调用,Native返回。
缺点:CallBack为异步操作,返回时机不确定
3. Promise
优点:JS调用,Native返回。
缺点:每次使用需要JS调用一次
了解了三者的通信方式,怎么能少了代码的描述!我们来看看代码如何实现。大致的实现步骤如下:
(1)定义Module类,继承ReactContextBaseJavaModule
在Module类中,我们定义交互的方法,例如RN调用Native的方法,Native调用RN的方法等。
(2)定义Package类,继承ReactPackage
实现Package的createNativeModules方法,将Module实例添加到集合。
(3)定义Application,继承ReactApplication
实现getPackages方法,将Package实例添加到getPackages下的集合。
4. 直传常量数据(原生向RN)
跨域传值,只能从原生端向RN端传递。RN端可通过 NativeModules.[module名].[参数名] 的方式获取
1.Module类中的核心代码
[java] view plain copy
- /**
- * 在rn代码里面是需要这个名字来调用该类的方法
- * @return
- */
- @Override
- public String getName() {
- return MODULE_NAME;
- }
名称可以自定义,对接时协商好即可。
[java] view plain copy
- /**
- * RN调用Native的方法
- * @param phone
- */
- @ReactMethod
- public void rnCallNative(String phone) {
- // 跳转到打电话界面
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_CALL);
- intent.setData(Uri.parse("tel:" + phone));
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 跳转需要添加flag, 否则报错
- mContext.startActivity(intent);
- }
在module中定义一个方法,并用@ReactMethod 注解标注:表明该方法会被RN调用。即被RN调用的原生方法必须使用@ReactMethod注解标注。
注意:RN层调用Native层进行界面跳转时,需要设置FLAG_ACTIVITY_NEW_TASK标志,否则会出现如下错误:
[java] view plain copy
- /**
- * Native调用RN
- * @param msg
- */
- public void nativeCallRn(String msg) {
- mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
- .emit(EVENT_NAME,msg);
- }
上面代码定义了原生方法,通过在Android层调用RN层。使用ReactContext的getJSModule方法,emit来发送消息。同样,emit的第一个参数要与RN层中addListener方法的第一个参数相同。
2.自定义Package的核心代码
[java] view plain copy
- /**
- * 通信Package类
- * Created by Song on 2017/2/17.
- */
- public class CommPackage implements ReactPackage {
- public CommModule mModule;
- /**
- * 创建Native Module
- * @param reactContext
- * @return
- */
- @Override
- public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
- List<NativeModule> modules = new ArrayList<>();
- mModule = new CommModule(reactContext);
- modules.add(mModule);
- return modules;
- }
- @Override
- public List<Class<? extends JavaScriptModule>> createJSModules() {
- return Collections.emptyList();
- }
- @Override
- public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
- return Collections.emptyList();
- }
- }
在createNativeModules方法中,初始化集合,并将module实例添加进集合,返回集合实例。
3.Application核心代码
[java] view plain copy
- private static final CommPackage mCommPackage = new CommPackage();
[java] view plain copy
- /**
- * 获取 reactPackage
- * @return
- */
- public static CommPackage getReactPackage() {
- return mCommPackage;
- }
在getPackages方法中,将Package实例添加到Arrays中即可完成注册。以上就是Android层核心代码配置,继续来看React Native层核心代码:
1.调用原生代码
[java] view plain copy
- /**
- * 调用原生代码
- */
- skipNativeCall() {
- let phone = '18637070949';
- NativeModules.commModule.rnCallNative(phone);
- }
在React Native层,通过NativeModules调用commModule,继而调用原生方法即可。注意:commModule要与Module类的getNames方法返回的名称对应。
2. 接收原生调用
[java] view plain copy
- /**
- * 接收原生调用
- */
- componentDidMount() {
- DeviceEventEmitter.addListener('nativeCallRn',(msg)=>{
- title = "React Native界面,收到数据:" + msg;
- ToastAndroid.show("发送成功", ToastAndroid.SHORT);
- })
- }
通过DeviceEventEmitter注册监听,类似于Android中的监听事件。第一个参数标识名称,要与Module中emit的Event Name相同。第二个参数即为处理回掉。
3.界面代码
[html] view plain copy
- render() {
- return (
- <View style={styles.container}>
- <Text style={styles.welcome} >
- {title}
- </Text>
- <Text style={styles.welcome} onPress={this.skipNativeCall.bind(this)}>
- 跳转到拨号界面
- </Text>
- <Image source={require('./images/ic.png')} />
- </View>
- );
- }
在Text中注册单击事件,RN层调用原生代码,跳转到拨号界面。
4.Android层调用RN的代码
[java] view plain copy
- /**
- * 向RN发送消息
- * @param v
- */
- public void sendMsgToRN(View v) {
- Log.e("---","sendMsgToRN");
- MainApplication.getReactPackage().mModule.nativeCallRn("hello");
- }
调用Module中定义的nativeCallRn方法,继而出发RN层代码。以上就是通过 RCTDeviceEventEmitter 模式进行通信交互。可以很清晰的看出,交互都是以主动方式为主。
RN中剩下的两种通信方式,存在一个共同的特点:
从RN层调用Native层,Native层处理完成后,回调RN层
直接看代码实现:
(1)Callback
同样还是在Module类中定义交互方法:
[java] view plain copy
- /**
- * Callback 方式
- * rn调用Native,并获取返回值
- * @param msg
- * @param callback
- */
- @ReactMethod
- public void rnCallNativeFromCallback(String msg, Callback callback) {
- // 1.处理业务逻辑...
- String result = "处理结果:" + msg;
- // 2.回调RN,即将处理结果返回给RN
- callback.invoke(result);
- }
RN中定义回调:
[java] view plain copy
- /**
- * Callback 通信方式
- */
- callbackComm(msg) {
- NativeModules.commModule.rnCallNativeFromCallback(msg,(result) => {
- ToastAndroid.show("CallBack收到消息:" + result, ToastAndroid.SHORT);
- })
- }
(2)Promise
Module类中定义交互方法:
[java] view plain copy
- /**
- * Promise 方式
- * @param msg
- * @param promise
- */
- @ReactMethod
- public void rnCallNativeFromPromise(String msg, Promise promise) {
- Log.e("---","adasdasda");
- // 1.处理业务逻辑...
- String result = "处理结果:" + msg;
- // 2.回调RN,即将处理结果返回给RN
- promise.resolve(result);
- }
RN中定义回调:
[java] view plain copy
- /**
- * Promise 通信方式
- */
- promiseComm(msg) {
- NativeModules.commModule.rnCallNativeFromPromise(msg).then(
- (result) =>{
- ToastAndroid.show("Promise收到消息:" + result, ToastAndroid.SHORT)
- }
- ).catch((error) =>{console.log(error)});
- }
布局中触发单击事件:
[html] view plain copy
- <Text style={styles.welcome} onPress={this.skipNativeCall.bind(this)}>
- 跳转到拨号界面
- </Text>
- <Text style={styles.welcome} onPress={this.callbackComm.bind(this,'callback发送啦')}>
- Callback通信方式
- </Text>
- <Text style={styles.welcome} onPress={this.promiseComm.bind(this,'promise发送啦')}>
- Promise通信方式
- </Text>
(3)直传常量数据(原生向RN)
自定义Module类中实现getConstants方法
[java] view plain copy
- @Nullable
- @Override
- public Map<String, Object> getConstants() {
- return super.getConstants();
- }
以上是默认实现,getConstants方法中调用了super.getConstants(),跟踪源码可以看到
[java] view plain copy
- /**
- * @return a map of constants this module exports to JS. Supports JSON types.
- */
- public @Nullable Map<String, Object> getConstants() {
- return null;
- }
从源码注释中可以看出,该方法是返回一个Map类型的常量,导出到JS端(即RN)。支持JSON 类型。所以,我们只需要重写方法,声明Map集合,向其中添加常量后,返回即可。所以就有了如下代码
[java] view plain copy
- @Nullable
- @Override
- public Map<String, Object> getConstants() {
- Map<String,Object> params = new HashMap<>();
- params.put("Constant","我是常量,传递给RN");
- return params;
- }
此时,在RN端,我们可以通过NativeModules来接收即可
[java] view plain copy
- componentWillMount() {
- let result = NativeModules.MyModule.Constant
- }
最终效果:
Android调用React Native:
React Native调用Android:
源码以上传到github,希望大家star,follow支持哦~
源码下载
转载https://blog.csdn.net/u013718120/article/details/55506238
以上是 React Native与Android通信交互 的全部内容, 来源链接: utcz.com/z/382611.html