你们吼,(◐‿◑)做为失踪人口回归,此次第二期,就让咱们来怼React Native的通讯,快速实现单独的React Native模块到APP里,愉悦吧骚年。至于为何要有这期?固然是为了愉悦的飙车啦ε-(´∀`; )。react
下方包含源码剧透,剧情略长,请紧张耐心的往下看。( ̄^ ̄)ゞ
文中标注有“【数字】”的是干货哟。android
本文前上部分主要拆解一些基础的原理,由浅到深;后半部分讲解集成模块实现,你也能够直接阅读后半部分,快速实现模块集成。文中着重在Android端帮助你们理解React Native。git
下方先提早介绍一些关键类。github
默认react-native init
建立的项目里,会有一个MainActivity
和一个MainApplication
。MainApplication
继承了ReactApplication
接口,接口只有一个方法:getReactNativeHost
。小程序
这个接口实如今Application,经过getApplication,你能够随时拿到ReactNativeHost
,它会帮你建立一个单例:ReactInstanceManager
做为管理器。ReactNativeHost
还能够配置一系列的行为,其中最关键的,即是getPackages
接口。微信小程序
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 -> ReactInstanceManager -> ReactPackage -> NativeModule -> CatalystInstance(这位就是负责发送的同志)微信
【1】因此只要实现了ReactPackage和NativeModule,将它注册到ReactNativeHost
或者ReactInstanceManager
,就能够在React Native中继承你原生的模块了。网络
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端监听页面的状态,会同时收到两个消息通知。
再深刻的咱们就先不追究,后面有深刻通讯相关的文章推荐,其中涉及到CatalystInstance
、ReactBridge
、BridgeCallback
等等,经过jni转为字符串,再拼接为命令和代码执行等原理,有兴趣的能够移步吸几口。
能够看出,ReactInstanceManager是其中的关键,不管哪里都有它的身影,ReactNativeHost的Package列表是给它,建立ReactContex也是它,其实加载JS的也是它,因此后半部分实现模块,其中很关键的就是它了。
实现一个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等等会互相干扰污染·····
1.一、以下图,首先你须要在布局中建立一个ReactRootView。
1.二、建立一个ReactInstanceManager,配置你须要支持的自定义选项,最后经过build(),实现一个XReactInstanceManagerImpl,将它这是给ReactRootView。
如上图,能够看到:
是否是很简单,这样你就能够经过原生的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。
【4】综合理解,React Native对于android back按键,是在onBackPressed中,把全部的back事件都发到js端,若是js端没监听,或者监听都返回了false,那么就会回到继承了DefaultHardwareBackBtnHandler接口,实现了invokeDefaultOnBackPressed的Activity处理。
(˶‾᷄ ⁻̫ ‾᷅˵)下方干货满满,请耐心吸食
首先咱们建立一个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端的交互,以下图。
createNativeModules
方法中,以下图。欧耶,终于码完了,你是否是对于React Native 相关的通讯机制,还有交互实现有了新的了解呢?若是你以为还不知足,这里推荐一个深度了解React Native通讯的系列。文中从android到js端,还有jni层面都作了详细的跟踪,有兴趣的可跳转观摩,下方连接。
React-Native系列Android——Native与Javascript通讯原理
项目相关的源码:github.com/CarGuo/Lear…
我的github:github.com/CarGuo