从Android到React Native开发(2、通讯与模块实现)

你们吼,(◐‿◑)做为失踪人口回归,此次第二期,就让咱们来怼React Native的通讯,快速实现单独的React Native模块到APP里,愉悦吧骚年。至于为何要有这期?固然是为了愉悦的飙车啦ε-(´∀`; )。react

下方包含源码剧透,剧情略长,请紧张耐心的往下看。( ̄^ ̄)ゞ
文中标注有“【数字】”的是干货哟。android

准备好接受新姿式了么

开始以前

 本文前上部分主要拆解一些基础的原理,由浅到深;后半部分讲解集成模块实现,你也能够直接阅读后半部分,快速实现模块集成。文中着重在Android端帮助你们理解React Native。git

下方先提早介绍一些关键类。github

  • ReactActivity:默认全部的Activity都继承它。
  • ReactNativeHost :帮你"hold"住ReactInstanceManager。
  • ReactActivityDelegate:ReactActivity的逻辑代理实现。
  • ReactRootView :React NativeUI的所在。
  • ReactInstanceManager:React Native的扛把子,抽象类。
  • XReactInstanceManagerImpl :ReactInstanceManager的实现类。
  • ReactContext: 管理React Native的状态等。
  • NativeModule:继承它的module能够在js端使用,其中就包括有DeviceEventManagerModule,与JS实现事件模式交互的module。
  • Callback/Promise: 回调接口,与js端交互。

开始目瞪口呆

1、上半部分

一、MainApplication

 默认react-native init建立的项目里,会有一个MainActivity和一个MainApplicationMainApplication继承了ReactApplication接口,接口只有一个方法:getReactNativeHost小程序

1.一、ReactNativeHost

 这个接口实如今Application,经过getApplication,你能够随时拿到ReactNativeHost,它会帮你建立一个单例:ReactInstanceManager做为管理器。ReactNativeHost还能够配置一系列的行为,其中最关键的,即是getPackages接口。微信小程序

默认在Application实现了ReactNativeHost

getPackages 接口返回了一系列的ReactPackage类,ReactPackage能够看做是,向ReactNative注册了原生模块,这样在JS中你也可使用原生模块的功能,按键第三方库时,react-native link命令,其中一个行为,就是在getPackages中帮你插入,库须要引用到的模块。react-native

 如上图,是MainReactPackage内部实现,MainReactPackage是官方的类,其中关联了不少NativeModule,Module中你能够经过@ReactMethod注解,指定一个方法为JS能够调用的方法,以下图的DetailModule,即是继承了NativeModule的JAVA端实现类,在js中引入。promise

总结一下,划重点Σ( ̄。 ̄ノ)ノ:
  • MainApplication继承了ReactApplication,返回了ReactNativeHost
  • ReactNativeHost里建立了ReactInstanceManager,而且实现了getPackages,返回了ReactPackage列表。
  • ReactInstanceManager在建立Builder时,把ReactPackage列表加入到管理器。
  • ReactPackage列表里面都关联了NativeModule的实现类。
  • NativeModule的实现类能够经过注解,相似@ReactMethod让原生方法能够被React调用。

粗略流程:
 MainApplication -> ReactApplication -> ReactNativeHost -> ReactInstanceManager -> ReactPackage -> NativeModule -> CatalystInstance(这位就是负责发送的同志)微信

【1】因此只要实现了ReactPackage和NativeModule,将它注册到ReactNativeHost或者ReactInstanceManager,就能够在React Native中继承你原生的模块了网络

二、ReactActivity

 MainActivity你们确定不陌生,默认react-native init建立的项目里,MainActivity十分简单,只有一个getMainComponentName,它就是告诉Avtivity,默认须要加载的js组件名(Component)是什么,而其他的事情,都是继承的ReactActivity帮你实现。

首先咱们直接来分析下顺序:

  • ReactActivity默认建立了一个ReactActivityDelegate
  • ReactActivityDelegate建立了一个单例的ReactInstanceManager(经过上面的ReactNativeHost)。
  • ReactInstanceManager(抽象类)内部建立了ReactRootView
  • ReactInstanceManager 的实现类为XReactInstanceManagerImpl
  • XReactInstanceManagerImpl在createReactContext 建立了ReactApplicationContext
  • ReactApplicationContext实现了生命状态事件的分发,通知js端Activity的状态。

结合上面 MainApplication部分:

  • ReactInstanceManager里面注册了ReactPackage
  • ReactPackage关联了NativeModule的实现类。
  • NativeModule能够经过增长注解的方法被JS端调用。

因此流程能够粗略认为是
一、MainApplication -> ReactApplication -> ReactNativeHost。
二、ReactActivity -> ReactActivityDelegate -> ReactNativeHost ->
ReactInstanceManager -> ReactContex -> ReactPackage -> NativeModule

例如,ReactActivity的OnResume事件流程:
一、ReactActivityDelegate.onResume();。
二、getReactNativeHost().getReactInstanceManager().onHostResume();。
三、ReactContext.onHostResume();。
四、AppStateModule.onHostResume();。
五、RCTDeviceEventEmitter 经过 emit("appStateDidChange", createAppStateEventMap());通知js。

【2】这里咱们须要注意,只要继承了ReactActivity,不管你实现了多少个Activity,它们的内部ReactInstanceManager都只有一个,消息会出现共享的状况。好比A页面onResume是,B页面就会onPause,若是你在JS端监听页面的状态,会同时收到两个消息通知。

 再深刻的咱们就先不追究,后面有深刻通讯相关的文章推荐,其中涉及到CatalystInstanceReactBridgeBridgeCallback等等,经过jni转为字符串,再拼接为命令和代码执行等原理,有兴趣的能够移步吸几口。

 能够看出,ReactInstanceManager是其中的关键,不管哪里都有它的身影,ReactNativeHost的Package列表是给它,建立ReactContex也是它,其实加载JS的也是它,因此后半部分实现模块,其中很关键的就是它了。

2、下半部分

实现一个React Native应用,有两种方法:
一、一种直接继承ReactActivity,指定js中须要加载的组件名字。
二、在布局中加入ReactRootView,经过ReactInstanceManager加载管理js。

 关于第一种,咱们不深刻展开,由于它的实现经过上面已经大体讲完,参考init下来的react工程,能够很简单的实现,他们共享Applicaton中的ReactNativeHost,和Host建立的ReactInstanceManager。

 那么咱们为何要讲第二种呢?这里首先讲解一个知识点:

【3】React Native在打包的时候,是把js代码打包成js bundle,js bundle就是压缩后的js代码,它放在android的assert文件下,启动React Native应用时默认加载它。

 既然如何,那么咱们是否能够修改js bundle的加载路径?固然能够啊,否则说个卵(╯‵□′)╯︵┻━┻。经过网络下载不一样的js bundle,加载实现不一样的React Native App,哇塞,这不就是简单的微信小程序么。

 ReactNativeHost也能够配置js bundle的文件路径,那么继承ReactActivity不是能够更简单的实现吗?不,由于继承ReactActivity,他们内部共享了一个ReactInstanceManager,做为单独的React Native程序模块,想一想消息、路由、store等等会互相干扰污染·····  

一、建立一个React Native 应用。

1.一、以下图,首先你须要在布局中建立一个ReactRootView。

1.二、建立一个ReactInstanceManager,配置你须要支持的自定义选项,最后经过build(),实现一个XReactInstanceManagerImpl,将它这是给ReactRootView。

如上图,能够看到:

  • setJSBundleFile,你能够指定加载bundle文件的路径
  • addPackge,增长你的React Native小程序支持的原生模块,其中MainReactPackage是必须的。
  • setJSMainModuleName指定了主js模块的名字。

 是否是很简单,这样你就能够经过原生的http,去下载和更新js bundle,而后加载显示,从而实现相似微信小程序的需求。

 固然,如上图,不要忘记给你的Activity继承DefaultHardwareBackBtnHandler接口,还有将activity的生命状态通知到js端。

1.3 DefaultHardwareBackBtnHandler

 这里要大篇幅讲解下,DefaultHardwareBackBtnHandler接口,经过它咱们能够总体了解,React Native从android端,到JS端对back按键事件的处理。

  • 首先Activity须要继承DefaultHardwareBackBtnHandler接口。DefaultHardwareBackBtnHandler只有一个invokeDefaultOnBackPressed方法。

  • ReactInstanceManager在onHostResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl);中须要传入activity和handler接口。

  • ReactInstanceManager.onBackPressed()会经过DeviceEventManagerModule,向js端发送了"hardwareBackPress"消息。

  • JS中,在BackAndrod类中,默认经过全局静态方法,注册了"hardwareBackPress"的监听。以下图所示,监听中判断全局Set表中的callBack,倒序循环判断,是否有callback,callback是否返回true,若是都没有,就调用exitApp。

  • BackAndroid.App()经过下图中的原生module,最终通过几回变换,会调用到上面Activity的DefaultHardwareBackBtnHandler接口,经过invokeDefaultOnBackPressed()响应。

  • 最后在invokeDefaultOnBackPressed中经过 super.onBackPressed();结束Activity的一辈子。

【4】综合理解,React Native对于android back按键,是在onBackPressed中,把全部的back事件都发到js端,若是js端没监听,或者监听都返回了false,那么就会回到继承了DefaultHardwareBackBtnHandler接口,实现了invokeDefaultOnBackPressed的Activity处理。

二、建立你的Moudle实现自定义交互

(˶‾᷄ ⁻̫ ‾᷅˵)下方干货满满,请耐心吸食

 首先咱们建立一个DetailMoudle继承ReactContextBaseJavaModule,以下图。

  • 经过getName指定了js端使用的名字。

  • 经过@ReactMethod注解指定了哪些方法能够被js端调用,js端能够传递指定类型的参数,这里注意【5】@ReactMethod的返回类型必定是void

  • 参数传递js端与android端对应以下图。

  • Callback/Promise 都是回调接口,promise有更多元化的回调选择。可是注意:【6】不管是Callback 仍是 Promise ,在执行invoke/(reject、resolve)以后,都会在js的消息队列中被销毁,不能再调用一次,也就是说全部的callback只能执行一次。

  • 你还能够经过消息机制实现android和js端的交互,以下图。

  • 以下图,经过继承ActivityEventListener,用ReactApplicationContext添加监听,能够方便的在module中监听activity返回。网上说的用消息阻塞队列的作法就算了吧。

  • 经过以下方法,能够在android的其余位置拿到module对象。

  • 建立一个DetailPackage 继承 ReactPackage,将建立好的DetailModule添加到createNativeModules方法中,以下图。

  • 最后将你的ReactPackage添加到你的ReactNativeHost或者ReactInstanceManager中。在js端经过下图方式调用。

 欧耶,终于码完了,你是否是对于React Native 相关的通讯机制,还有交互实现有了新的了解呢?若是你以为还不知足,这里推荐一个深度了解React Native通讯的系列。文中从android到js端,还有jni层面都作了详细的跟踪,有兴趣的可跳转观摩,下方连接。

React-Native系列Android——Native与Javascript通讯原理

项目相关的源码:github.com/CarGuo/Lear…

我的github:github.com/CarGuo

还记得我么
相关文章
相关标签/搜索