前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React native和原生之间的通信

React native和原生之间的通信

作者头像
xiangzhihong
发布2018-02-05 15:29:24
4.6K1
发布2018-02-05 15:29:24
举报
文章被收录于专栏:向治洪向治洪

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

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

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

2)使用Promise来实现。

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

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

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

代码语言:js
复制
/*原生模块可以在没有被调用的情况下往JavaScript发送事件通知。 
    最简单的办法就是通过RCTDeviceEventEmitter, 
    这可以通过ReactContext来获得对应的引用,像这样:*/ 
 public static void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap paramss)  
    {  
        System.out.println("reactContext="+reactContext);  
 
        reactContext  
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)  
                .emit(eventName, paramss);  
 
    }  

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

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

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

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

如下所示:

代码语言:java
复制
public class MyModule extends ReactContextBaseJavaModule {  
 
 private BluetoothAdapter mBluetoothAdapter = null;  
 public MyModule(ReactApplicationContext reactContext) {  
 super(reactContext);  
 
        原生类1.MyContext=reactContext;  
 
 
    }  
.......以下写被@ReactNative所标注的方法  
............................  
...................  
}  

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

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

代码语言:java
复制
WritableMap event = Arguments.createMap();  
sendEvent(MyContext, "EventName",event);  

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

然后使用componentWillMount建立监听。

代码如下:

代码语言:js
复制
componentWillMount(){    
 
                    DeviceEventEmitter.addListener('EventName', function() {    
 
                         alert("send success");    
                       });   
 
 
}  

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

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

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

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

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

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

代码如下:

ManiActivity.Java

代码语言:js
复制
package com.ywq;  
 
import com.facebook.react.ReactActivity;  
 
public class MainActivity extends ReactActivity {  
 
 /** 
     * Returns the name of the main component registered from JavaScript. 
     * This is used to schedule rendering of the component. 
     */ 
 @Override 
 protected String getMainComponentName() {  
 return "ywq";  
    }  
}  

ManiApplication.java

代码语言:js
复制
package com.ywq;  
 
import android.app.Application;  
import android.util.Log;  
 
import com.facebook.react.ReactApplication;  
import com.facebook.react.ReactInstanceManager;  
import com.facebook.react.ReactNativeHost;  
import com.facebook.react.ReactPackage;  
import com.facebook.react.shell.MainReactPackage;  
 
import java.util.Arrays;  
import java.util.List;  
 
public class MainApplication extends Application implements ReactApplication {  
 
 private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {  
 @Override 
 protected boolean getUseDeveloperSupport() {  
 return BuildConfig.DEBUG;  
    }  
 
 @Override 
 protected List<ReactPackage> getPackages() {  
 return Arrays.<ReactPackage>asList(  
 new MainReactPackage(),  
 new MyPackage()  
      );  
    }  
  };  
 
 @Override 
 public ReactNativeHost getReactNativeHost() {  
 return mReactNativeHost;  
  }  
}  

MyModule.java

代码语言:java
复制
package com.ywq;  
 
import com.facebook.react.bridge.ReactApplicationContext;  
import com.facebook.react.bridge.ReactContextBaseJavaModule;  
import com.facebook.react.bridge.ReactMethod;  
 
/** 
 * Created by Administrator on 2016/10/30. 
 */ 
 
public class MyModule extends ReactContextBaseJavaModule {  
 
 public MyModule(ReactApplicationContext reactContext) {  
 
 super(reactContext);  
 
 //给上下文对象赋值 
        Test.myContext=reactContext;  
    }  
 
 @Override 
 public String getName() {  
 
 return "MyModule";  
    }  
 
 
 @ReactMethod 
 public void  NativeMethod()  
    {  
 //调用Test类中的原生方法。 
 new Test().fun();  
    }  
}  

MyPackage.java

代码语言:java
复制
package com.ywq;  
 
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;  
 
/** 
 * Created by Administrator on 2016/10/30. 
 */ 
 
public class MyPackage implements ReactPackage {  
 @Override 
 public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {  
 
        List<NativeModule> modules=new ArrayList<>();  
        modules.add(new MyModule(reactContext));  
 
 return modules;  
    }  
 
 @Override 
 public List<Class<? extends JavaScriptModule>> createJSModules() {  
 return Collections.emptyList();  
    }  
 
 @Override 
 public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {  
 return Collections.emptyList();  
    }  
}  

Test.java

代码语言:java
复制
package com.ywq;  
 
import android.provider.Settings;  
import android.support.annotation.Nullable;  
 
import com.facebook.react.bridge.Arguments;  
import com.facebook.react.bridge.ReactContext;  
import com.facebook.react.bridge.WritableMap;  
import com.facebook.react.modules.core.DeviceEventManagerModule;  
 
/** 
 * Created by Administrator on 2016/10/30. 
 */ 
 
public class Test {  
 
 //定义上下文对象 
 public static ReactContext myContext;  
 
 //定义发送事件的函数 
 public void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params)  
    {  
        System.out.println("reactContext="+reactContext);  
 
        reactContext  
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)  
                .emit(eventName,params);  
    }  
 
 public void fun()  
    {  
 //在该方法中开启线程,并且延迟3秒,然后向JavaScript端发送事件。 
 new Thread(new Runnable() {  
 @Override 
 public void run() {  
 
 try {  
                    Thread.sleep(3000);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
 
 //发送事件,事件名为EventName 
                WritableMap et= Arguments.createMap();  
                sendEvent(myContext,"EventName",et);  
 
 
            }  
        }).start();  
 
    }  
 
 
}  

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

代码语言:java
复制
/** 
 * Sample React Native App 
 * https://github.com/facebook/react-native 
 * @flow 
 */ 
 
import React, { Component } from 'react';  
import {  
 AppRegistry,  
  StyleSheet,  
  Text,  
  DeviceEventEmitter,  
  NativeModules,  
  View  
} from 'react-native';  
 
export default class ywq extends Component {  
 
    componentWillMount(){    
 //监听事件名为EventName的事件 
                    DeviceEventEmitter.addListener('EventName', function() {    
 
 
 
                         alert("send success");    
 
                       });   
 
 
}  
 
  constructor(props) {  
 super(props);  
 this.state = {  
        content: '这个是预定的接受信息',  
    }  
}  
 
  render() {  
 return (  
      <View style={styles.container}>  
 
        <Text style={styles.welcome}  
         onPress={this.callNative.bind(this)}  
        >  
          当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。  
          前端一直在监听该事件,如果收到,则给出alert提示!  
        </Text>  
 
        <Text style={styles.welcome} >  
        {this.state.content}  
         </Text>  
 
 
      </View>  
    );  
  }  
 
  callNative()  
  {  
    NativeModules.MyModule.NativeMethod();  
  }  
 
 }  
 
const styles = StyleSheet.create({  
  container: {  
    flex: 1,  
    justifyContent: 'center',  
    alignItems: 'center',  
    backgroundColor: '#F5FCFF',  
  },  
  welcome: {  
    fontSize: 20,  
    textAlign: 'center',  
    margin: 10,  
  },  
  instructions: {  
    textAlign: 'center',  
    color: '#333333',  
    marginBottom: 5,  
  },  
});  
 
AppRegistry.registerComponent('ywq', () => ywq);  

运行结果如下所示:

点击之前:

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

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

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

代码语言:js
复制
/** 
 * Sample React Native App 
 * https://github.com/facebook/react-native 
 * @flow 
 */ 
 
import React, { Component } from 'react';  
import {  
 AppRegistry,  
  StyleSheet,  
  Text,  
  DeviceEventEmitter,  
  NativeModules,  
  View  
} from 'react-native';  
 
export default class ywq extends Component {  
 
    componentWillMount(){    
 //监听事件名为EventName的事件 
                    DeviceEventEmitter.addListener('EventName', function() {    
 
 this.showState();  
 
                         alert("send success");    
 
                       });   
 
 
}  
 
  constructor(props) {  
 super(props);  
 this.state = {  
        content: '这个是预定的接受信息',  
    }  
}  
 
  render() {  
 return (  
      <View style={styles.container}>  
 
        <Text style={styles.welcome}  
         onPress={this.callNative.bind(this)}  
        >  
          当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。  
          前端一直在监听该事件,如果收到,则给出alert提示!  
        </Text>  
 
        <Text style={styles.welcome} >  
        {this.state.content}  
         </Text>  
 
 
      </View>  
    );  
  }  
 
  callNative()  
  {  
    NativeModules.MyModule.NativeMethod();  
  }  
 
  showState()  
  {  
 this.setState({content:'已经收到了原生模块发送来的事件'})  
  }  
}  
 
const styles = StyleSheet.create({  
  container: {  
    flex: 1,  
    justifyContent: 'center',  
    alignItems: 'center',  
    backgroundColor: '#F5FCFF',  
  },  
  welcome: {  
    fontSize: 20,  
    textAlign: 'center',  
    margin: 10,  
  },  
  instructions: {  
    textAlign: 'center',  
    color: '#333333',  
    marginBottom: 5,  
  },  
});  
 
AppRegistry.registerComponent('ywq', () => ywq);  

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

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

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

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

修改UI代码如下:

代码语言:java
复制
/** 
 * Sample React Native App 
 * https://github.com/facebook/react-native 
 * @flow 
 */ 
 
import React, { Component } from 'react';  
import {  
 AppRegistry,  
  StyleSheet,  
  Text,  
  DeviceEventEmitter,  
  NativeModules,  
  View  
} from 'react-native';  
 
export default class ywq extends Component {  
 
    componentWillMount(){    
 //监听事件名为EventName的事件 
 
                    DeviceEventEmitter.addListener('EventName', ()=> {    
 
 this.showState();  
                         alert("send success");    
 
                       });   
 
}  
 
  constructor(props) {  
 super(props);  
 this.state = {  
        content: '这个是预定的接受信息',  
    }  
}  
 
  render() {  
 return (  
      <View style={styles.container}>  
 
        <Text style={styles.welcome}  
         onPress={this.callNative.bind(this)}  
        >  
          当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。  
          前端一直在监听该事件,如果收到,则给出alert提示!  
        </Text>  
 
        <Text style={styles.welcome} >  
        {this.state.content}  
         </Text>  
 
 
      </View>  
    );  
  }  
 
  callNative()  
  {  
    NativeModules.MyModule.NativeMethod();  
  }  
 
  showState()  
  {  
 this.setState({content:'已经收到了原生模块发送来的事件'})  
  }  
}  
 
const styles = StyleSheet.create({  
  container: {  
    flex: 1,  
    justifyContent: 'center',  
    alignItems: 'center',  
    backgroundColor: '#F5FCFF',  
  },  
  welcome: {  
    fontSize: 20,  
    textAlign: 'center',  
    margin: 10,  
  },  
  instructions: {  
    textAlign: 'center',  
    color: '#333333',  
    marginBottom: 5,  
  },  
});  
 
AppRegistry.registerComponent('ywq', () => ywq);  

运行之后,界面刷新了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-11-27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档