最近偷懒了一段时间(折腾了下小程序、跨平台开发框架Weex / React Native / Flutter),到现在接入RN混合开发也已经七八个月的时间了,今天针对RN在Android混编项目做个整体的复盘反思。以下内容是之前总结,本次不再重复记录。

  1. 简述RN集成到Android原生项目
  2. RN与Android原生的消息通信
  3. RN使用Android原生控件或自定义组件
  4. RN修改React Native端口号本地调试
  5. 将RN项目打包成离线包
  6. React Native Linking与 Android原生页面路由跳转实现
  7. Android项目集成RN混淆打包问题

本次记录不作为使用指南记录,因此不再描述项目初始化等相关方面,需要的可以参考上面链接,这里主要站在我们业务选择和使用RN的角度来整体上分析跨平台RN开发的优缺点,及对React Native与 Android 混编项目简单做下复盘反思。

一、跨平台RN开发的优缺点:

  1. 优点:

    • 提高研发和测试效率
    • 各终端逻辑保持统一

    之前Android、iOS、M同一需求需三端开发人员各自去实现,以各自对需求的理解、各自的实现方式去码不同的代码,各自的逻辑和展示也可能就各不相同,很难保证功能一致性,自然测试人员需要针对三端各自测试,逻辑bug产生相对比较零散,各端各不相同,验证也相对比较耗时耗力,采用RN同一功能,同一套代码逻辑方式,测试起来发现逻辑bug相对统一,一些平台差异性兼容性bug除外,大大提高测试效率,同时各终端业务逻辑也相对统一,提高了研发效率。

  2. 缺点:
    因平台差异性可能会存在一些兼容性问题,如果想在前期就能抹平各端差异性问题及解决各平台兼容型问题,就需要RN开发人员熟悉Android、IOS、Web三端开发技术,对技术广度稍微有点高。

二、React Native在Android混编项目中的页面跳转和方法调用

React Native 与 Android 混编项目复盘反思_第1张图片 Android与RN通信.png

大致通过上面这张简图来描述下:

  1. 页面跳转(RN与Android原生)
    调查背景:在设计与RN交互时,并不是仅站在Android一端的角度去设计,而是考虑通用型,尽量用RN本身特性去抹平差异性,避免RN在代码层面进行差异化处理,比如说页面跳转处理:

    • Android的页面跳转是通过Intent跳转
    • RN是通过路由(M版也通过路由跳转)

    如果保持各自特性,则两者直接页面互相跳转就需要原生借助JS暴露接口给RN来实现了,这样的话RN就需要根据终端环境进行差异化处理,为了避免RN在代码层面进行差异化处理,尽量寻找统一性方案确保整个项目的统一,通过调查发现RN提供的Linking方式进行跳转,那么就有两个问题,RN怎么拿?原生怎么传?然后通过源码发现RN分别针对Android和IOS进行了封装映射,我们只需要把数据传送到对应的位置即可,

    const LinkingManager =    Platform.OS === 'android'    ? NativeModules.IntentAndroid : NativeModules.LinkingManager;

    在Android中对应的是IntentAndroid,查看对应的源码:

    /** * Return the URL the activity was started with ** @param promise a promise which is resolved with the initial URL*/ @ReactMethod public void getInitialURL(Promise promise) {   try {     Activity currentActivity = getCurrentActivity();     String initialURL = null;     if (currentActivity != null) {       Intent intent = currentActivity.getIntent();       String action = intent.getAction();       Uri uri = intent.getData();       if (Intent.ACTION_VIEW.equals(action) && uri != null) {         initialURL = uri.toString();       }     }     promise.resolve(initialURL);   } catch (Exception e) {     promise.reject(new JSApplicationIllegalArgumentException(         "Could not get the initial URL : " + e.getMessage()));   } }

    通过上面源码也就了解了Android与RN如何根据Linking进行页面跳转,我先按照这种形式在Android上进行测试发现可行,当然也有bug,就是拿的时候可能为空,调查发现RN与原生页面装载之前就调用这个方法导致拿不到上下文,只要创建rootview就会执行rn的生命周期,而此时rN与原生还没有绑定,后来发现RN是能监听到原生页面的活动状态,此时再去获取路由即可。详细内容可参考React Native Linking与 Android原生页面路由跳转实现

  2. 方法调用
    RN通信原理简单地讲就是,一方native(java)将其部分方法注册成一个映射表,另一方(js)再在这个映射表中查找并调用相应的方法,而Bridge担当两者间桥接的角色。
    其实方法调用大致分为2种情况:

    • Android主动向JS端传递事件、数据
    • JS端主动向Android询问获取事件、数据

    RN调用Android需要module名和方法名相同,而Android调用RN只需要方法名相同。
    (1)RCTDeviceEventEmitter 事件方式
    ​ 优点:可任意时刻传递,Native主导控制。
    (2)Callback 回调方式
    ​ 优点:JS调用,Native返回。
    ​ 缺点:CallBack为异步操作,返回时机不确定
    (3)Promise
    ​ 优点:JS调用,Native返回。
    ​ 缺点:每次使用需要JS调用一次
    (4)直传常量数据(原生向RN)
    ​ 跨域传值,只能从原生端向RN端传递。RN端可通过 NativeModules.[module名].[参数名] 的方式获取。

    注意:RN层调用NativeModule层进行界面跳转时,需要设置FLAG_ACTIVITY_NEW_TASK标志。

三、Andorid 与 RN 传参数据类型映射关系:

Android React Native 备注
Boolean Boolean
Integer Number
Double Number
Float Number
String String
Callback function
ReadableMap / WritableMap Object
ReadableArray / WritableArray Object

观察着8种参数类型发现,其中有ReadableMapReadableArray类型,对应JavaScriptObject。而在Java原生中,可以发现facebook定义了ReadableArrayReadableMap接口,一层一层找一下,找到了WritableArrayWritableMap接口,以及实现了他们的WritableNativeArrayWritableNativeMap,我尝试利用WritableNativeArray push了几个参数,成功的传递到了参数:

//Android    @ReactMethod    public void show(Callback callback) {        WritableArray writableArray = new WritableNativeArray();        writableArray.pushString("one");        writableArray.pushString("two");        writableArray.pushString("three");        callback.invoke(writableArray);    }    //React Native    MyTest.show((result)=> {                ToastAndroid.show("结果是:" + result[2], ToastAndroid.SHORT);            }        );
     //Android    @ReactMethod    public void show(Callback callback) {        WritableMap writableMap = new WritableNativeMap();        writableMap.putString("1", "first");        writableMap.putString("2", "second");        writableMap.putString("3", "third");        callback.invoke(writableMap);    }        //React Native    MyTest.show((result)=> {                ToastAndroid.show("结果是:" + result["2"], ToastAndroid.SHORT);            }        );

备注: 如何更好地将RN与原生进行参数传递呢?虽说上面的映射关系可以让我们去准确的传递参数,但是比如说在Android原生中ReadableMap / WritableMap对应着RN中的 Object, 但是我们原生里面并不会全局使用ReadableMap / WritableMap来替换现有的Map或者HashMap吧,为尽量避免RN的侵入型,我们需要Native Module层进行抽象封装处理,将RN中的数据类型与Android原生的数据类型进行互转,稍后会整理相关转化工具类,方便Android与原生快速交互。

经过一段时间的梳理,不管是前面讲过的知识点还是没讲过的(预加载/热更新)后面都会在一个工具库中体现,旨在创建一个能够快速轻便集成RN与Android混编项目,优化两者相互通信方式(各自使用各自熟悉的数据格式,抹平差异性),以及RN bundle在Android中实现按需加载以及热更新功能的工具库。

更多相关文章

  1. iOS开发周报:Swift 项目合并 Android 分支,App Store 开展 “Apps
  2. 华软项目总结
  3. android项目中在webview中打开pdf
  4. Android小项目之--找到本地联络人并向其发邮件(附源码)
  5. Android 项目导入eclipse中报错但找不到错误地方的解决方法
  6. android 优秀开源项目收集
  7. Android项目源码混淆问题解决方法
  8. Android 项目在Eclipse中的目录结构

随机推荐

  1. Android(安卓)Drawable Resource学习(一)、
  2. Android(安卓)AsyncTask
  3. 创建android Notification
  4. Android(安卓)imageView图片按比例缩放
  5. Android之提高Service优先级总结及androi
  6. Android(安卓)anr介绍
  7. android studio无法更新之解决方案
  8. android布局及常见布局属性 二
  9. 详解 Android(安卓)的 Activity 组件
  10. Android(安卓)集成FaceBook广告