美文网首页React Native开发经验集React Native开发ReactNative系列
reactnative ~ android 模块通讯混合跳转方案

reactnative ~ android 模块通讯混合跳转方案

作者: DaZenD | 来源:发表于2018-08-17 19:03 被阅读5次

rn ~ android 模块通讯混合跳转方案详解

android原生 接入rn模块

原生接入rn + 通信详解资料

android原生 ~ rn 通信

Android系统为我们提供了webview来加载网页,为了让webview加载的网页可以与App交互,系统提供了一套机制帮助我们更方便的实现通信。同样为了实现React Native与原生App之间的通信,FB也实现了自己的一套交互机制。

通信原理

原生接入rn + 通信详解资料

native 调用 rn

RCTDeviceEventEmitter

js端通过RCTDeviceEventEmitter监听native端发送的事件,来实现原生端主动到js端的通信。

就像Android中的广播,iOS中的通知中心

原生端:

public void accessRn() {
    WritableMap params = Arguments.createMap();
    params.putString("result", xxx);
    sendEvent(getReactApplicationContext(), "Native2Rn", params);
}

private void sendEvent(ReactContext reactContext,String eventName, @Nullable WritableMap params) {
    reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
            .emit(eventName, params);
}

上述代码表示原生发送一个名为“Native2Rn”的事件给rn,如下,rn中会监听名为“Native2Rn”的事件

js端:

componentDidMount() {
    //注册扫描监听
    DeviceEventEmitter.addListener('Native2Rn',this.onScanningResult);
}
onScanningResult = (e)=> {
    this.setState({
        scanningResult: e.result,
    });
    // DeviceEventEmitter.removeListener('onScanningResult',this.onScanningResult);//移除扫描监听
}

在JS中通过DeviceEventEmitter注册监听了名为“Native2Rn”的事件,当原生模块发出名为“Native2Rn”的事件后,绑定在该事件上的onScanningResult = (e)会被回调。 然后通过e.result就可获得事件所携带的数据

注意: 如果在JS中有多处注册了onScanningResult事件,那么当原生模块发出事件后,这几个地方会同时收到该事件

rn 调用 native

上面通信资料中有讲解,rn调用native,需要native在module中通过@ReactMethod注解暴露方法给rn,然后rn就可以通过NativeModules组件访问到native的方法

callback

    /**
    * RN调用Android原生,使用Callback方式
    * 注意Callback参数引入的必须是react的,别引入错了
    * */
    @ReactMethod
    public void rnCallAndroidWithCallback(String msg, Callback callback) {
        //处理msg...
        String result = msg + "被Android原生处理啦,我要告诉RN处理结果";

        //回调,可以有多个参数callback.invoke(result,"1","abc");
        callback.invoke(result);
    }

JS端:

     CustomNativeModule = NativeModules.CustomNativeModule;
     CustomNativeModule. rnCallAndroidWithCallback("msg", (result) => {
     console.log(result);
  });

promise

/**
     * RN调用Android原生,使用Promise方式
     *
     * */
    @ReactMethod
    public void rnCallAndroidWithPromise(String msg, Promise promise) {
        //处理msg...
        String result = msg + "被Android原生处理啦,我要告诉RN处理结果";

        //回调
        promise.resolve(result);

        //error
//        promise.reject(XXXXXXXX);
    }

注意:在原生模块中Promise类型的参数要放在最后一位,这样JS调用的时候才能返回一个Promise

JS端:

  • 同步方式:
     CustomNativeModule = NativeModules.CustomNativeModule;
     try {
    var {
        result,
    } = await CustomNativeModule.rnCallAndroidWithPromise("msg");
  } catch (e) {
    console.error(e);
  }
  • 异步方式:
     CustomNativeModule = NativeModules.CustomNativeModule;
     CustomNativeModule.rnCallAndroidWithPromise("msg").then(e=>{
    this.setState({
      result:msg
    })
  }).catch(error=>{
    console.log(error);
  });

注意:上面代码所在函数,函数名前加 async。如:async func() {xxx}

页面跳转方案

基于上面的通信讲解,native和rn能够相互给对方喊话,就可以跟对方说我要你干什么了。。

native 跳转 rn

基于android原生和rn通信讲解:入参 > rn判断加载不同的rn模块

原生跳转入参

无回调方式:native通过intent向rn传值

Android端Module新建方法

  /**
     * 获取当前activity传递的intent
     */
    @ReactMethod
    public void getDataFromIntent(Callback success, Callback error) {
        try {
            Activity activity = getCurrentActivity();
            if (activity != null) {
                String flag = activity.getIntent().getStringExtra("flag");
                if (TextUtils.isEmpty(flag)) {
                    flag = "default value";
                }
                success.invoke(flag);
            }
        } catch (Exception e) {
            error.invoke(e.getMessage());
            throw new JSApplicationIllegalArgumentException(
                    "Could not open the activity : " + e.getMessage());
        }
    }

JS端调用

     CustomNativeModule = NativeModules.CustomNativeModule;
     CustomNativeModule.getDataFromIntent(success => {
         console.warn(success);
     }, error => {
         console.warn(error);
     });

rn处理入参

根据native 到 rn的传参,在index.js中根据flag判断渲染不同的rn模块页面即可,原理跟ios是一样的,只是传参有一些差别。所以,这块,android,ios 页面跳转方案一样

startActivityForResult方式:rn关闭后,native拿到返回值

Android端

    /**
     * native 打开js for result
     * js 的回调
     */
    @ReactMethod
    public void finishActivity(String result) {
        Activity currentActivity = getCurrentActivity();
        Intent intent = new Intent();
        intent.putExtra("result", result);
        currentActivity.setResult(100, intent);
        currentActivity.finish();
    }

JS端

    finish() {
        let CustomNativeModule = NativeModules.CustomNativeModule;
        CustomNativeModule.finishActivity('result');
    }

从上面的两种通讯方式可以理解到,原生 ~ rn 就是通过一个桥梁,向对方喊话,然后各干各的,因为跨语言的,不可能相互调用。只能通过一种协议。就是我们的module

rn 跳转 native

基于android原生和rn通信讲解:调用原生暴露的方法进行跨端控制

无回调:startActivity

Android端

    /**
     * js跳转nativeActivity
     */
    @ReactMethod
    public void startActivityByString(String activityName) {
        try {
            Activity currentActivity = getCurrentActivity();
            if (null != currentActivity) {
                Class aimActivity = Class.forName(activityName);
                Intent intent = new Intent(currentActivity, aimActivity);
                currentActivity.startActivity(intent);
            }
        } catch (Exception e) {
            throw new JSApplicationIllegalArgumentException(
                    "Could not open the activity : " + e.getMessage());
        }
    }

JS端

    startNative(activityName) {
        CustomNativeModule.startActivityByString(text)
    }

有回调:startActivityForResult

Android端
Module

    @ReactMethod
    public void startActivityForResult(String activityName, int requestCode, final Callback successCallback, Callback erroCallback) {
        try {
            Activity currentActivity = getCurrentActivity();
            if (null != currentActivity) {
                Class aimActivity = Class.forName(activityName);
                Intent intent = new Intent(currentActivity, aimActivity);
                currentActivity.startActivityForResult(intent, requestCode);

                new Thread() {

                    @Override
                    public void run() {
                        String result = null;
                        try {
                            result = BaseApplication.myBlockingQueue.take();
                            successCallback.invoke(result);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }.start();

            }
        } catch (Exception e) {
            erroCallback.invoke(e.getMessage());
            throw new JSApplicationIllegalArgumentException(
                    "Could not open the activity : " + e.getMessage());
        }
    }

原生Activity

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK && requestCode == 100) {
            String result = data.getStringExtra("result");
            if (TextUtils.isEmpty(result)) {
                BaseApplication.myBlockingQueue.add(result);
            } else {
                BaseApplication.myBlockingQueue.add("no data");
            }
        } else {
            BaseApplication.myBlockingQueue.add("null");
        }
    }

初始化ArrayBlockingQueue

public static ArrayBlockingQueue<String> myBlockingQueue = new ArrayBlockingQueue<String>(1);

JS端:

    startNativeForResult(text) {
        CustomNativeModule.startActivityForResult(text, 100, 
            (succ)=>{ToastAndroid.show(succ, ToastAndroid.SHORT)}, 
            (err)=>{console.warn(err)})
    }

其他相关资料

个人rn相关专题

相关文章

网友评论

    本文标题:reactnative ~ android 模块通讯混合跳转方案

    本文链接:https://www.haomeiwen.com/subject/aybtiftx.html