React Native0.61进阶之与Android端传递消息

转载自:https://blog.csdn.net/u013718120/article/details/55506238

RN与Andorid通信的方式大概总结了有以下四种:

  1. RCTDeviceEventEmitter 事件方式

  2. Callback 回调方式

  3. Promise 信任方式

  4. 直传常量数据

 

优缺点:

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类中的核心代码

    /**
     * 在rn代码里面是需要这个名字来调用该类的方法
     * @return
     */
    @Override
    public String getName() {
        return MODULE_NAME;
    }

名称可以自定义,对接时协商好即可。

    /**
     * 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标志,否则会出现错误:

    /**
     * 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的核心代码

/**
 * 通信Package类
 * 
 */
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核心代码

private static final CommPackage mCommPackage = new CommPackage();

   /**
     * 获取 reactPackage
     * @return
     */
    public static CommPackage getReactPackage() {
        return mCommPackage;
    }

 

在getPackages方法中,将Package实例添加到Arrays中即可完成注册。以上就是Android层核心代码配置,继续来看React Native层核心代码:

1.调用原生代码

   /**
    * 调用原生代码
    */
    skipNativeCall() {
       let phone = '18637070949';
       NativeModules.commModule.rnCallNative(phone);
    }

在React Native层,通过NativeModules调用commModule,继而调用原生方法即可。注意:commModule要与Module类的getNames方法返回的名称对应。

2. 接收原生调用

   /**
    * 接收原生调用
    */
   componentDidMount() {
       DeviceEventEmitter.addListener('nativeCallRn',(msg)=>{
            title = "React Native界面,收到数据:" + msg;
            ToastAndroid.show("发送成功", ToastAndroid.SHORT);
       })
   }

通过DeviceEventEmitter注册监听,类似于Android中的监听事件。第一个参数标识名称,要与Module中emit的Event Name相同。第二个参数即为处理回掉。

3.界面代码

 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的代码

    /**
     * 向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类中定义交互方法:

    /**
     * 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中定义回调:

   /**
    * Callback 通信方式
    */
    callbackComm(msg) {
        NativeModules.commModule.rnCallNativeFromCallback(msg,(result) => {
             ToastAndroid.show("CallBack收到消息:" + result, ToastAndroid.SHORT);
        })
    }

(2)Promise

Module类中定义交互方法:

    /**
     * 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中定义回调:

    /**
     * Promise 通信方式
     */
    promiseComm(msg) {
        NativeModules.commModule.rnCallNativeFromPromise(msg).then(
            (result) =>{
                ToastAndroid.show("Promise收到消息:" + result, ToastAndroid.SHORT)
            }
        ).catch((error) =>{console.log(error)});
    }

布局中触发单击事件:

 <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方法

    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        return super.getConstants();
    }

以上是默认实现,getConstants方法中调用了super.getConstants(),跟踪源码可以看到

  /**
   * @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集合,向其中添加常量后,返回即可。所以就有了如下代码

    @Nullable
    @Override
    public Map<String, Object> getConstants() {
        Map<String,Object> params = new HashMap<>();
        params.put("Constant","我是常量,传递给RN");
        return params;
    }

此时,在RN端,我们可以通过NativeModules来接收即可

componentWillMount() {
	let result = NativeModules.MyModule.Constant
}

 源码以上传到github,希望大家star,follow支持哦~

  源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值