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

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相关专题

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

推荐阅读更多精彩内容