美文网首页Android开发经验谈React NativeAndroid开发
React Native 与 Android 混编项目复盘反思

React Native 与 Android 混编项目复盘反思

作者: 闲庭 | 来源:发表于2019-06-27 22:10 被阅读9次

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

  1. RN与Android原生的消息通信
  2. RN使用Android原生控件或自定义组件
  3. RN加载Gif图片及手动修改React Native端口号
  4. 将RN项目打包成离线包
  5. React Native Linking与 Android原生页面路由跳转实现
  6. Android项目集成RN混淆打包问题

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

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

  1. 优点:

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

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

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

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

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层调用Native层进行界面跳转时,需要设置FLAG_ACTIVITY_NEW_TASK标志。

例如:下面是RCTDeviceEventEmitter事件的简单事例,稍后封装下更方便与原生的通信交互。

public class EventEmitter {
    private static final String TAG = "EventEmitter";
    // 在ReactPackage中的createNativeModules()初始化,RNEventEmitter.setReactContext(reactContext);
    private static ReactApplicationContext mReactContext;

    public static void setReactContext(ReactApplicationContext mReactContext) {
        RNEventEmitter.mReactContext = mReactContext;
    }
    /**
     * 显示RN中loading
     * @param data show:显示,false:隐藏
     */
    public static void showLoading(boolean show) {
        nativeCallRn("showloading", show);
    }
    public static void nativeCallRn(String eventName, Object msg) {
        if (mReactContext == null) {
            Log.e(TAG, "ReactContext is null");
            return;
        }
      mReactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName,msg);
    }
}

RN中接收原生消息:

 /**
    * 接收原生调用
    */
   componentDidMount() {
       DeviceEventEmitter.addListener('showLoading',(msg)=>{
            ToastAndroid.show("发送成功"+msg, ToastAndroid.SHORT);
       })
     //通过DeviceEventEmitter注册监听,类似于Android中的监听事件。第一个参数标识名称,要与Module中emit的Event Name相同。第二个参数即为处理回调时间。
   }

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

Android React Native 备注
Boolean Bool
Integer Number
Double Number
Float Number
String String
Callback function
ReadableMap / WritableMap Object RN中的对象
ReadableArray / WritableArray Array

观察着8种参数类型发现,其中有ReadableMapReadableArray类型,对应JavaScriptObjectArray。而在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与原生快速交互。

相关文章

网友评论

    本文标题:React Native 与 Android 混编项目复盘反思

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