1. 程式人生 > >React Native之Android原生通過DeviceEventEmitter傳送訊息給js

React Native之Android原生通過DeviceEventEmitter傳送訊息給js

1 問題

Android原生向js發訊息,並且可以攜帶資料

2 實現原理

Android原生可以使用RCTEventEmitter來註冊事件,然後這裡需要指定事件的名字,然後在js那端進行監聽同樣事件的名字監聽,就可以收到訊息得到資料

Android註冊關鍵程式碼

reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);

這裡的eventName和下面的'EventName'的值需要保持一致.

js那端的監聽

   componentWillMount(){  
      //監聽事件名為EventName的事件
      DeviceEventEmitter.addListener('EventName', function() {  
          alert("Android send js msg success");  
      });                                
    }

3 程式碼實現

可以先參考我前面幾篇部落格的部分程式碼和類檔案

還是基於上面的文章,然後我這邊多加了一個Test.java類,檔案如下,這裡主要是註冊

package com.pro_react;


import android.content.Context;
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;


public class Test {

    //定義上下文物件
    public ReactContext myContext;

    public Test(ReactContext context) {
        this.myContext = context;
    }

    //定義傳送事件的函式
    public void sendEventToUi(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
    }

    public void sendMsg()
    {
        //在該方法中開啟執行緒,並且延遲1秒,然後向JavaScript端傳送事件。
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //傳送事件,事件名為EventName
                WritableMap wm = Arguments.createMap();
                sendEventToUi(myContext,"EventName", wm);
            }
        }).start();
    }
}

然後在MyToastModule.java檔案裡面增加了,當js點選文字觸發showMyName函式的時候,我們這邊就向js傳送訊息,MyToastModule.java檔案如下

package com.pro_react;

import android.content.Context;
import android.util.Log;
import android.widget.Toast;

import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

/**
 * Created by chenyu on 9/15/18.
 */

public class MyToastModule extends ReactContextBaseJavaModule {

    public ReactContext mContext;
    public MyToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
        mContext = reactContext;
    }

    /**
     * getName方法返回一個字串名字,就是js中的模組名
     * 到時候我們寫js的時候需要匯入這個模組,這裡我用的是MyToast
     */
    @Override
    public String getName() {
        return "MyToast";
    }

    /**
     * 這是js呼叫的方法,需要使用註解@ReactMethod,返回型別必須為void
     */
    @ReactMethod
    public void show() {
        Toast.makeText(getReactApplicationContext(), "I am chenyu", Toast.LENGTH_SHORT).show();
    }

    @ReactMethod(isBlockingSynchronousMethod = true)
    public String showMyName() {
        NotificationUtil util = NotificationUtil.getInstance(mContext);
        //util.showMessage();
        //向ui傳送訊息
        new Test(mContext).sendMsg();
        return "chenyu1";
    }

}

App.js檔案修改如下

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, NativeModules, DeviceEventEmitter} from 'react-native';

const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
  android:
    'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
});
var myAndroidToast = NativeModules.MyToast;
type Props = {};
export default class App extends Component<Props> {
   
   componentWillMount(){  
      //監聽事件名為EventName的事件
      DeviceEventEmitter.addListener('EventName', function() {  
          alert("Android send js msg success");  
      });                                
    }

    constructor(props){
        super(props);
        this.state={
            myName:'chenzixuan',
        }
    }
  
  render() {
    return (
      <View style={styles.container}>
        <Text onPress={()=> this._androidShowMsg()} style={styles.welcome}>Welcome to React Native!</Text>
        <Text style={styles.instructions}>To get started, edit App.js</Text>
        <Text style={styles.instructions}>{instructions}</Text>
        <Text style={styles.instructions}>{this.state.myName}</Text>
      </View>
    );
  }

    _androidShowMsg = () => {
       var value = myAndroidToast.showMyName();
       this.setState({myName:value});
        
    };
}

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

4 測試結果

這裡修改了App.js,所以需要新生成android.index.bundle檔案,執行命令如下

react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res

然後再執行

react-native run-android

效果如下

點選Welcome to React Native效果如下