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

简介:

大家吼,(◐‿◑)作为失踪人口回归,这次第二期,就让我们来怼React Native的通信,快速实现单独的React Native模块到APP里,愉悦吧骚年。至于为什么要有这期?当然是为了愉悦的飙车啦ε-(´∀`; )。

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

准备好接受新姿势了么

开始之前

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

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

  • 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 和一个MainApplication MainApplication继承了ReactApplication接口,接口只有一个方法:getReactNativeHost

1.1、ReactNativeHost

 这个接口实现在Application,通过getApplication,你可以随时拿到ReactNativeHost,它会帮你创建一个单例:ReactInstanceManager 作为管理器。ReactNativeHost还可以配置一系列的行为,其中最关键的,便是getPackages接口。

默认在Application实现了ReactNativeHost

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

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

总结一下,划重点Σ( ̄。 ̄ノ)ノ:
  • 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中继承你原生的模块了

2、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端调用。

所以流程可以粗略认为是
1、MainApplication -> ReactApplication -> ReactNativeHost。
2、ReactActivity -> ReactActivityDelegate -> ReactNativeHost ->
ReactInstanceManager -> ReactContex -> ReactPackage -> NativeModule

例如,ReactActivity的OnResume事件流程:
1、ReactActivityDelegate.onResume();。
2、getReactNativeHost().getReactInstanceManager().onHostResume();。
3、ReactContext.onHostResume();。
4、AppStateModule.onHostResume();。
5、RCTDeviceEventEmitter 通过 emit("appStateDidChange", createAppStateEventMap());通知js。

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

 再深入的我们就先不追究,后面有深入通信相关的文章推荐,其中涉及到CatalystInstance ReactBridgeBridgeCallback等等,通过jni转为字符串,再拼接为命令和代码执行等原理,有兴趣的可以移步吸几口。

 可以看出,ReactInstanceManager是其中的关键,无论哪里都有它的身影,ReactNativeHost的Package列表是给它,创建ReactContex也是它,其实加载JS的也是它,所以后半部分实现模块,其中很关键的就是它了。

二、下半部分

实现一个React Native应用,有两种方法:
1、一种直接继承ReactActivity,指定js中需要加载的组件名字。
2、在布局中加入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、创建一个React Native 应用。

1.1、如下图,首先你需要在布局中创建一个ReactRootView。

1.2、创建一个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处理。

2、创建你的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通信原理

项目相关的源码:https://github.com/CarGuo/LearnProject

RN完整学习项目:https://github.com/CarGuo/GSYGithubAPP

个人github:https://github.com/CarGuo

还记得我么

目录
相关文章
|
29天前
|
编解码 开发工具 Android开发
Android平台RTMP直播推送模块技术接入说明
大牛直播SDK跨平台RTMP直播推送模块,始于2015年,支持Windows、Linux(x64_64架构|aarch64)、Android、iOS平台,支持采集推送摄像头、屏幕、麦克风、扬声器、编码前、编码后数据对接,功能强大,性能优异,配合大牛直播SDK的SmartPlayer播放器,轻松实现毫秒级的延迟体验,满足大多数行业的使用场景。RTMP直播推送模块数据源,支持编码前、编码后数据对接
|
9天前
|
消息中间件 前端开发
React技术栈-组件间通信的2种方式
本文介绍了React技术栈中组件间通信的两种方式:通过props传递数据和使用消息发布(publish)-订阅(subscribe)机制,并通过实例代码展示了如何使用PubSubJS库实现跨组件通信。
36 11
React技术栈-组件间通信的2种方式
|
30天前
|
编解码 网络协议 前端开发
如何实现Android平台GB28181设备接入模块按需打开摄像头并回传数据
后台采集摄像头,如果想再进一步扩展,可以把android平台gb28181的camera2 demo,都移植过来,实现功能更强大的国标设备侧,这里主要是展示,收到国标平台侧的回传请求后,才打开摄像头,才开始编码打包,最大限度的减少资源的占用
|
30天前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧
我们在做Android平台GB28181设备对接模块的时候,遇到这样的技术需求,开发者希望能以后台服务的形式运行程序,国标平台侧没有视频回传请求的时候,仅保持信令链接,有发起视频回传请求或语音广播时,打开摄像头,并实时回传音视频数据或接收处理国标平台侧发过来的语音广播数据。
|
13天前
|
监控 Java 开发工具
如何快速对接Android平台GB28181接入模块(SmartGBD)
大牛直播SDK推出的Android平台GB28181接入SDK(SmartGBD),可实现不具备国标音视频能力的 Android终端,通过平台注册接入到现有的GB/T28181—2016服务,可用于如执法记录仪、智能安全帽、智能监控、智慧零售、智慧教育、远程办公、明厨亮灶、智慧交通、智慧工地、雪亮工程、平安乡村、生产运输、车载终端等场景,可能是业内为数不多功能齐全性能优异的商业级水准GB28181接入SDK。
|
29天前
|
监控 开发工具 Android开发
结合GB/T28181规范探讨Android平台设备接入模块心跳实现
本文介绍了GB28181标准中的状态信息报送机制,即心跳机制,用于监控设备与服务器间的连接状态。根据国标GB/T28181-2016,设备在异常时需立即发送状态信息,在正常状态下则按固定间隔(默认60秒)定期发送。若连续三次(默认值)未收到心跳,则视为离线。文章展示了在Android平台的GB28181设备接入模块(SmartGBD)中,如何调整心跳间隔为20秒及超时次数为3次,并给出了心跳消息的示例和异常处理代码片段。对于希望深入了解或遇到问题的开发者,作者提供了进一步交流的机会。
|
29天前
|
编解码 API 开发工具
Android平台轻量级RTSP服务模块二次封装版调用说明
本文介绍了Android平台上轻量级RTSP服务模块的二次封装实践,旨在简化开发流程,让开发者能更专注于业务逻辑。通过`LibPublisherWrapper`类提供的API,可在应用中轻松初始化RTSP服务、配置视频参数(如分辨率、编码类型)、启动与停止RTSP服务及流发布,并获取RTSP会话数量。此外,还展示了如何处理音频和视频数据的采集与推送。最后,文章提供了从启动服务到销毁资源的完整示例,帮助开发者快速集成实时流媒体功能。
|
29天前
|
编解码 开发工具 Android开发
Android平台轻量级RTSP服务模块技术接入说明
为满足内网无纸化/电子教室等内网超低延迟需求,避免让用户配置单独的服务器,大牛直播SDK在推送端发布了轻量级RTSP服务SDK。 轻量级RTSP服务解决的核心痛点是避免用户或者开发者单独部署RTSP或者RTMP服务,实现本地的音视频数据(如摄像头、麦克风),编码后,汇聚到内置RTSP服务,对外提供可供拉流的RTSP URL,轻量级RTSP服务,适用于内网环境下,对并发要求不高的场景,支持H.264/H.265,支持RTSP鉴权、单播、组播模式,考虑到单个服务承载能力,我们支持同时创建多个RTSP服务,并支持获取当前RTSP服务会话连接数。
|
2月前
|
前端开发 JavaScript Android开发
React Native跨平台开发实战
【7月更文挑战第21天】React Native为跨平台移动应用开发提供了一种高效且强大的解决方案。通过本文的学习,你应该能够掌握React Native的基本概念和实战步骤,并开始在你的项目中使用React Native进行开发。随着你对React Native的深入理解,你将能够利用其强大的功能来构建更加复杂和高效的移动应用。
|
30天前
|
Web App开发 前端开发 JavaScript
React——前端开发中模块与组件【四】
React——前端开发中模块与组件【四】
25 0

热门文章

最新文章