React native 与Android原生交互方式(一)

前言##

最近在做React Native开发的时候避免不了的需要原生模块和JS之间进行交互,其实RN和原生的通信大致分为两种情况;一种是Android主动向RN端发送事件和数据,另外一种是RN端被动向Android询问获取事件和数据,接下来的几篇文章将向大家分享原生模块向JS交互的几种方式。

1、发送事件的方式

2、callback方式

3、Promise方式

由于篇幅原因本文只对发送事件的方式进行详细介绍

发送事件的方式

使用了React Native的RCTDeviceEventEmitter,通过消息机制来实现,原生可以向JS传递事件而不需要直接的调用,就像我们android中的广播。
下面通就像大家暂时通过RCTDeviceEventEmitter来向JS传递事件。
原生模块中(Android端):
首先定义Module类:MyModule.java

public class MyModule extends ReactContextBaseJavaModule {
    private final String TAG = MyModule.class.getName();

    public MyModule(ReactApplicationContext reactContext) {
        super(reactContext);

        //给上下文对象赋值
        Test.mContext = reactContext;

    }

    //不能用return tag 来实现 不然不能调用方法...原因不理解
    @Override
    public String getName() {
        return "MyModule";
    }


    @ReactMethod
    public void callNativeBySend(){
        //调用Test类中的原生方法。
        Log.e("wangfang","called send");
        new Test().fun();
    }


}

发送事件的代码在Test类中,
Test.java代码段如下:


public class Test {

    public static ReactContext mContext;
    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(mContext,"EventName",et);


            }
        }).start();

    }
    //定义发送事件的函数
    public  void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params)
    {
        System.out.println("reactContext="+reactContext);

        reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName,params);//原生调Rn
    }
}

从上述代码可以看到,原生向JS模块发送了一个名为“EventName”的事件,并携带了"et"作为参数,那大家肯定会问JS中如何接收事件并进行处理呢,别急。。。。
先把原生的代码说完,得把模块添加到包中
MyPackage代码如下:

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();
    }
}

接着RN依附的Activity代码如下:

public class RnAndroidCommuActivity extends ReactActivity{


    @Override
    public String getMainComponentName() {
        return "testNative";
    }
}

原生的Activity的代码:

public class NativeActivity extends Activity {
    private Button btnGoReact;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnGoReact = (Button)this.findViewById(R.id.btn_go_react);
        btnGoReact.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(NativeActivity.this,RnAndroidCommuActivity.class);
                intent.putExtra("result","native go to react");
                startActivity(intent);
            }
        });

    }

activity_main资源文件的代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.wangfang.rnproject.MainActivity">

    <Button
        android:id="@+id/btn_go_react"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="原生界面跳转React界面"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

还有清单文件 这里就不贴代码了,相信做过Android的项目都知道咋写吧。。。
RN端的代码:

import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  DeviceEventEmitter,
  NativeModules,
  View,
  TextInput
} from 'react-native';
import React from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  DeviceEventEmitter,
  NativeModules,
  View,
  TextInput
} from 'react-native';
export class RnAndroidCommunication extends React.Component{
  componentWillMount(){
    DeviceEventEmitter.addListener("EventName",()=>{
      this.showState();
      alert("send event success");
    });
  }

  constructor(props){
    super(props);
    this.state={
      content:"这是个预定的接受消息"
    }

  }

  render(){
    return (
      <View style = {myStyles.container}>

        <Text style = {myStyles.welcome} onPress={this.callNative.bind(this)}>
            当你点我的时候会调用原生方法,原生方法延迟3s后会向前端发送事件。
            前端一直在监听该事件,如果收到,则给出alert提示! send 方式
        </Text>
       
        <Text style = {myStyles.instructions}>
            {this.state.content}
        </Text>

      </View>

    );

  }
  
  callNative(){
      console.log(" js called by send");

      NativeModules.MyModule.callNativeBySend();
  }
  showState(){
    this.setState({content:"已经收到了原生模块发送来的事件,send event 方式"});
  }

}
const myStyles = 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('testNative', () => RnAndroidCommunication);

在JS中通过 DeviceEventEmitter 注册监听了名为“”的事件,当原生模块发出名为“EventName”的事件后,绑定在该事件上的 EventName = () 会被回调。 然后通过就可获得事件所携带的数据,并执行回调函数,进行页面显示灯。
心得:如果在JS中有多处注册了 EventName 事件,那么当原生模块发出事件后,这些地方会同时收到该事件。不过大家也可以通过 DeviceEventEmitter.removeListener('onScanningResult',this.onScanningResult) 来移除对名为“EventName”事件的监听。

下一篇:React native 与Android原生交互方式(二)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容