React native和原生之间的通信

来源:互联网 发布:期权模拟交易软件 编辑:程序博客网 时间:2024/05/29 10:08

RN中文网关于原生模块(Android)的介绍可以看到,RN前端与原生模块之

间通信,主要有三种方法:

1)使用回调函数Callback,它提供了一个函数来把返回值传回给JavaScript。

2)使用Promise来实现。

3)原生模块向JavaScript发送事件。

关于使用回调,这是最简单的一种通信,这里可以看看官网的实现,今天要讲的是滴三种由原生模块向JavaScript发送事件。

(1)首先,你需要定义一个发送事件的方法。如下所示:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /*原生模块可以在没有被调用的情况下往JavaScript发送事件通知。 
  2.     最简单的办法就是通过RCTDeviceEventEmitter, 
  3.     这可以通过ReactContext来获得对应的引用,像这样:*/  
  4.     public static void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap paramss)  
  5.     {  
  6.         System.out.println("reactContext="+reactContext);  
  7.   
  8.         reactContext  
  9.                 .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)  
  10.                 .emit(eventName, paramss);  
  11.   
  12.     }  

 

其中方法名可以任意,但是参数不可改变。该方法可以放在你要复用的原生类中(即为原生类1)。

需要注意的是,由于版本问题,该函数中的参数reactContext有可能为null,此时会报NullPointException的错误。所以我们需要手动给reactContext赋值,见步骤2.

(2)我们在原生类1中,定义变量public static ReactContext  MyContext;

然后在我们自定义的继承至ReactContextBaseJavaModule的类中给reactContext赋值。

 

如下所示:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. public class MyModule extends ReactContextBaseJavaModule {  
  2.   
  3.     private BluetoothAdapter mBluetoothAdapter = null;  
  4.     public MyModule(ReactApplicationContext reactContext) {  
  5.         super(reactContext);  
  6.   
  7.         原生类1.MyContext=reactContext;  
  8.   
  9.           
  10.     }  
  11. .......以下写被@ReactNative所标注的方法  
  12. ............................  
  13. ...................  
  14. }  

 

此时,reactContext将不会是null。也就不会报错。

 

(3)在某个原生函数中向JavaScript发送事件。如下所示:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. WritableMap event = Arguments.createMap();  
  2. sendEvent(MyContext, "EventName",event);  


(4)在RN前端监听事件。首先导入DeviceEventEmitter,即import{ DeviceEventEmitter } from 'react-native'

然后使用componentWillMount建立监听。

 

代码如下:

[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. componentWillMount(){    
  2.     
  3.                     DeviceEventEmitter.addListener('EventName'function() {    
  4.                            
  5.                          alert("send success");    
  6.                        });   
  7.   
  8.                                
  9. }  

 

注意:该监听必须放在class里边,和render、const对齐。

 

下边展示一个完整Demo,Demo功能如下:

 

(1)JavaScript端在监听一个事件。

(2)点击前端某行文字,调用原生方法。

(3)在原生方法中,延迟3s后向前端发送对应事件。

(4)前端接收到事件后,给出alert提示。

 

代码如下:

ManiActivity.Java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.ywq;  
  2.   
  3. import com.facebook.react.ReactActivity;  
  4.   
  5. public class MainActivity extends ReactActivity {  
  6.   
  7.     /** 
  8.      * Returns the name of the main component registered from JavaScript. 
  9.      * This is used to schedule rendering of the component. 
  10.      */  
  11.     @Override  
  12.     protected String getMainComponentName() {  
  13.         return "ywq";  
  14.     }  
  15. }  


ManiApplication.java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.ywq;  
  2.   
  3. import android.app.Application;  
  4. import android.util.Log;  
  5.   
  6. import com.facebook.react.ReactApplication;  
  7. import com.facebook.react.ReactInstanceManager;  
  8. import com.facebook.react.ReactNativeHost;  
  9. import com.facebook.react.ReactPackage;  
  10. import com.facebook.react.shell.MainReactPackage;  
  11.   
  12. import java.util.Arrays;  
  13. import java.util.List;  
  14.   
  15. public class MainApplication extends Application implements ReactApplication {  
  16.   
  17.   private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {  
  18.     @Override  
  19.     protected boolean getUseDeveloperSupport() {  
  20.       return BuildConfig.DEBUG;  
  21.     }  
  22.   
  23.     @Override  
  24.     protected List<ReactPackage> getPackages() {  
  25.       return Arrays.<ReactPackage>asList(  
  26.           new MainReactPackage(),  
  27.               new MyPackage()  
  28.       );  
  29.     }  
  30.   };  
  31.   
  32.   @Override  
  33.   public ReactNativeHost getReactNativeHost() {  
  34.       return mReactNativeHost;  
  35.   }  
  36. }  


MyModule.java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.ywq;  
  2.   
  3. import com.facebook.react.bridge.ReactApplicationContext;  
  4. import com.facebook.react.bridge.ReactContextBaseJavaModule;  
  5. import com.facebook.react.bridge.ReactMethod;  
  6.   
  7. /** 
  8.  * Created by Administrator on 2016/10/30. 
  9.  */  
  10.   
  11. public class MyModule extends ReactContextBaseJavaModule {  
  12.   
  13.     public MyModule(ReactApplicationContext reactContext) {  
  14.   
  15.         super(reactContext);  
  16.   
  17.         //给上下文对象赋值  
  18.         Test.myContext=reactContext;  
  19.     }  
  20.   
  21.     @Override  
  22.     public String getName() {  
  23.   
  24.         return "MyModule";  
  25.     }  
  26.   
  27.   
  28.     @ReactMethod  
  29.     public void  NativeMethod()  
  30.     {  
  31.         //调用Test类中的原生方法。  
  32.         new Test().fun();  
  33.     }  
  34. }  


MyPackage.java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.ywq;  
  2.   
  3. import com.facebook.react.ReactPackage;  
  4. import com.facebook.react.bridge.JavaScriptModule;  
  5. import com.facebook.react.bridge.NativeModule;  
  6. import com.facebook.react.bridge.ReactApplicationContext;  
  7. import com.facebook.react.uimanager.ViewManager;  
  8.   
  9. import java.util.ArrayList;  
  10. import java.util.Collections;  
  11. import java.util.List;  
  12.   
  13. /** 
  14.  * Created by Administrator on 2016/10/30. 
  15.  */  
  16.   
  17. public class MyPackage implements ReactPackage {  
  18.     @Override  
  19.     public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {  
  20.   
  21.         List<NativeModule> modules=new ArrayList<>();  
  22.         modules.add(new MyModule(reactContext));  
  23.   
  24.         return modules;  
  25.     }  
  26.   
  27.     @Override  
  28.     public List<Class<? extends JavaScriptModule>> createJSModules() {  
  29.         return Collections.emptyList();  
  30.     }  
  31.   
  32.     @Override  
  33.     public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {  
  34.         return Collections.emptyList();  
  35.     }  
  36. }  


 

Test.java

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.ywq;  
  2.   
  3. import android.provider.Settings;  
  4. import android.support.annotation.Nullable;  
  5.   
  6. import com.facebook.react.bridge.Arguments;  
  7. import com.facebook.react.bridge.ReactContext;  
  8. import com.facebook.react.bridge.WritableMap;  
  9. import com.facebook.react.modules.core.DeviceEventManagerModule;  
  10.   
  11. /** 
  12.  * Created by Administrator on 2016/10/30. 
  13.  */  
  14.   
  15. public class Test {  
  16.   
  17.      //定义上下文对象  
  18.     public static ReactContext myContext;  
  19.   
  20.     //定义发送事件的函数  
  21.     public  void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params)  
  22.     {  
  23.         System.out.println("reactContext="+reactContext);  
  24.   
  25.         reactContext  
  26.                 .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)  
  27.                 .emit(eventName,params);  
  28.     }  
  29.   
  30.     public  void fun()  
  31.     {  
  32.         //在该方法中开启线程,并且延迟3秒,然后向JavaScript端发送事件。  
  33.         new Thread(new Runnable() {  
  34.             @Override  
  35.             public void run() {  
  36.   
  37.                 try {  
  38.                     Thread.sleep(3000);  
  39.                 } catch (InterruptedException e) {  
  40.                     e.printStackTrace();  
  41.                 }  
  42.   
  43.                //发送事件,事件名为EventName  
  44.                 WritableMap et= Arguments.createMap();  
  45.                 sendEvent(myContext,"EventName",et);  
  46.   
  47.   
  48.             }  
  49.         }).start();  
  50.   
  51.     }  
  52.   
  53.   
  54. }  


 

前端index.android.js代码如下:

[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Sample React Native App 
  3.  * https://github.com/facebook/react-native 
  4.  * @flow 
  5.  */  
  6.   
  7. import React, { Component } from 'react';  
  8. import {  
  9.  AppRegistry,  
  10.   StyleSheet,  
  11.   Text,  
  12.   DeviceEventEmitter,  
  13.   NativeModules,  
  14.   View  
  15. } from 'react-native';  
  16.   
  17. export default class ywq extends Component {  
  18.   
  19.     componentWillMount(){    
  20.                        //监听事件名为EventName的事件  
  21.                     DeviceEventEmitter.addListener('EventName'function() {    
  22.                            
  23.                          
  24.   
  25.                          alert("send success");    
  26.   
  27.                        });   
  28.   
  29.                                  
  30. }  
  31.   
  32.   constructor(props) {  
  33.     super(props);  
  34.     this.state = {  
  35.         content: '这个是预定的接受信息',  
  36.     }  
  37. }  
  38.   
  39.   render() {  
  40.     return (  
  41.       <View style={styles.container}>  
  42.   
  43.         <Text style={styles.welcome}  
  44.          onPress={this.callNative.bind(this)}  
  45.         >  
  46.           当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。  
  47.           前端一直在监听该事件,如果收到,则给出alert提示!  
  48.         </Text>  
  49.           
  50.         <Text style={styles.welcome} >  
  51.         {this.state.content}  
  52.          </Text>  
  53.   
  54.   
  55.       </View>  
  56.     );  
  57.   }  
  58.   
  59.   callNative()  
  60.   {  
  61.     NativeModules.MyModule.NativeMethod();  
  62.   }  
  63.    
  64.  }  
  65.   
  66. const styles = StyleSheet.create({  
  67.   container: {  
  68.     flex: 1,  
  69.     justifyContent: 'center',  
  70.     alignItems: 'center',  
  71.     backgroundColor: '#F5FCFF',  
  72.   },  
  73.   welcome: {  
  74.     fontSize: 20,  
  75.     textAlign: 'center',  
  76.     margin: 10,  
  77.   },  
  78.   instructions: {  
  79.     textAlign: 'center',  
  80.     color: '#333333',  
  81.     marginBottom: 5,  
  82.   },  
  83. });  
  84.   
  85. AppRegistry.registerComponent('ywq', () => ywq);  


运行结果如下所示:

点击之前:


 

调用原生方法并且等待3s后:


 

 

 

再说一个值得注意的地方,一般我们在接收到原生模块主动发来的事件时,都会进行一些操作,如更新UI,而不仅仅是弹出alert 。

例如我们需要更新UI,代码如下:

[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Sample React Native App 
  3.  * https://github.com/facebook/react-native 
  4.  * @flow 
  5.  */  
  6.   
  7. import React, { Component } from 'react';  
  8. import {  
  9.  AppRegistry,  
  10.   StyleSheet,  
  11.   Text,  
  12.   DeviceEventEmitter,  
  13.   NativeModules,  
  14.   View  
  15. } from 'react-native';  
  16.   
  17. export default class ywq extends Component {  
  18.   
  19.     componentWillMount(){    
  20.                       //监听事件名为EventName的事件  
  21.                     DeviceEventEmitter.addListener('EventName'function() {    
  22.                            
  23.                          this.showState();  
  24.   
  25.                          alert("send success");    
  26.   
  27.                        });   
  28.   
  29.                                  
  30. }  
  31.   
  32.   constructor(props) {  
  33.     super(props);  
  34.     this.state = {  
  35.         content: '这个是预定的接受信息',  
  36.     }  
  37. }  
  38.   
  39.   render() {  
  40.     return (  
  41.       <View style={styles.container}>  
  42.   
  43.         <Text style={styles.welcome}  
  44.          onPress={this.callNative.bind(this)}  
  45.         >  
  46.           当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。  
  47.           前端一直在监听该事件,如果收到,则给出alert提示!  
  48.         </Text>  
  49.           
  50.         <Text style={styles.welcome} >  
  51.         {this.state.content}  
  52.          </Text>  
  53.   
  54.   
  55.       </View>  
  56.     );  
  57.   }  
  58.   
  59.   callNative()  
  60.   {  
  61.     NativeModules.MyModule.NativeMethod();  
  62.   }  
  63.    
  64.   showState()  
  65.   {  
  66.        this.setState({content:'已经收到了原生模块发送来的事件'})  
  67.   }  
  68. }  
  69.   
  70. const styles = StyleSheet.create({  
  71.   container: {  
  72.     flex: 1,  
  73.     justifyContent: 'center',  
  74.     alignItems: 'center',  
  75.     backgroundColor: '#F5FCFF',  
  76.   },  
  77.   welcome: {  
  78.     fontSize: 20,  
  79.     textAlign: 'center',  
  80.     margin: 10,  
  81.   },  
  82.   instructions: {  
  83.     textAlign: 'center',  
  84.     color: '#333333',  
  85.     marginBottom: 5,  
  86.   },  
  87. });  
  88.   
  89. AppRegistry.registerComponent('ywq', () => ywq);  

很明显:当收到事件时,改变一个文本框的内容,即更新UI。

运行结果如下,说明在此function中不能使用this,也就是我们并不能更新UI。


那我们能做到在接收到事件后更新UI等后续操作吗?

使用胖箭头函数(Fat arrow functions)

修改UI代码如下:

[javascript] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Sample React Native App 
  3.  * https://github.com/facebook/react-native 
  4.  * @flow 
  5.  */  
  6.   
  7. import React, { Component } from 'react';  
  8. import {  
  9.  AppRegistry,  
  10.   StyleSheet,  
  11.   Text,  
  12.   DeviceEventEmitter,  
  13.   NativeModules,  
  14.   View  
  15. } from 'react-native';  
  16.   
  17. export default class ywq extends Component {  
  18.   
  19.     componentWillMount(){    
  20.                       //监听事件名为EventName的事件  
  21.                      
  22.                     DeviceEventEmitter.addListener('EventName', ()=> {    
  23.                            
  24.                          this.showState();  
  25.                          alert("send success");    
  26.   
  27.                        });   
  28.                   
  29. }  
  30.   
  31.   constructor(props) {  
  32.     super(props);  
  33.     this.state = {  
  34.         content: '这个是预定的接受信息',  
  35.     }  
  36. }  
  37.   
  38.   render() {  
  39.     return (  
  40.       <View style={styles.container}>  
  41.   
  42.         <Text style={styles.welcome}  
  43.          onPress={this.callNative.bind(this)}  
  44.         >  
  45.           当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。  
  46.           前端一直在监听该事件,如果收到,则给出alert提示!  
  47.         </Text>  
  48.           
  49.         <Text style={styles.welcome} >  
  50.         {this.state.content}  
  51.          </Text>  
  52.   
  53.   
  54.       </View>  
  55.     );  
  56.   }  
  57.   
  58.   callNative()  
  59.   {  
  60.     NativeModules.MyModule.NativeMethod();  
  61.   }  
  62.    
  63.   showState()  
  64.   {  
  65.        this.setState({content:'已经收到了原生模块发送来的事件'})  
  66.   }  
  67. }  
  68.   
  69. const styles = StyleSheet.create({  
  70.   container: {  
  71.     flex: 1,  
  72.     justifyContent: 'center',  
  73.     alignItems: 'center',  
  74.     backgroundColor: '#F5FCFF',  
  75.   },  
  76.   welcome: {  
  77.     fontSize: 20,  
  78.     textAlign: 'center',  
  79.     margin: 10,  
  80.   },  
  81.   instructions: {  
  82.     textAlign: 'center',  
  83.     color: '#333333',  
  84.     marginBottom: 5,  
  85.   },  
  86. });  
  87.   
  88. AppRegistry.registerComponent('ywq', () => ywq);  
运行之后,界面刷新了。



0 1
原创粉丝点击