演讲实录——React-native技术在腾讯课堂中的实践及优化 [复制链接]

2019-5-13 10:10
九霄逆鳞 阅读:392 评论:0 赞:1
Tag:  

本文来自2019安卓巴士开发者大会现场实录,由于录入匆忙,内容可能存在偏差,欢迎大家扫描文末二维码查看现场实录视频和下载大会完整PPT。演讲人:王华杰

大家好!我叫王华杰,来自腾讯在线教育部,主要做腾讯课堂app的开发工作,这次分享的题目是RN技术在腾讯课堂中的实践和优化。


首先我们看一下RN在腾讯课堂的使用情况。腾讯课堂App首页共有4个TAG,其中“首页”和“分类”两个页面是采用RN技术开发,一开始腾讯课堂首页TAG是native代码实现,后来才换成RN技术来实现,那么为什么腾讯课堂会在首页这种重要场景选择用RN技术来实现呢?



首先我们来看一下移动开发中的技术选型,在RN出来之前,移动开发基本有两种技术方案,一种是H5方案,在app中嵌入H5的页面,一种是直接采用native代码写的页面,这两种方案各有优点和缺点。H5实现的页面呢,他具有开发效率非常高,而且是跨平台支持的,H5写一套页面可以同时跑在Android和iOS上,还有重要的优点就是可动态发布,不需要跟随app的版本,但是他的缺点就是,体验相对差了点,性能也比原生的页面差,调用原生能力也比较差。而native技术开发的页面呢,开发效率比较低,而且跨平台比较难,基本是android和iOS各写一套代码。动态更新也很困难,一般都是要通过发版本来解决,而且发版本后新版本的普及也需要很长时间的。但是采用native技术开发的页面也有他的好处,首先他体验好,性能高,调用原生能力也非常强。



那么有没有一种解决方案能够把两者的优势综合在一起呢?答案是有的,那就是RN。RN是采用javascript语言来写具有原生体验app一种手段,他的基本原理就是,用js来描述UI逻辑,渲染则是使用Native的view来渲染上屏,这样他就综合了H5和native的优点,具有开发效率高,可跨平台和动态发布,而且高性能体验好。腾讯课堂是怎么引入RN的呢。



腾讯课堂对RN有一个很大的拓展和改造,原生的RN针对的业务场景比较单一,一般bundle是打包成一个包,稳定性和性能不够好。启动速度相对native有比较大的差距,官方的组件API比较少,整体不够优秀。我们在原生基础上做了拓展和改造,首先是对多业务场景做了优化,还有它的稳定性,我们解决了大部分稳定性问题,而且提高了页面的加载速度。功能上支持了业务的分包加载,还支持bundle发布管理,还有动态更新,还定制了很多高性能的组件和API。



整体架构,主要分三部分:工具部分包括代码的和打包分包工具。Native能力部分我们会提供很多高性能的API和组件,API有存储、下载等。发布部分有发布系统,会做一个离线包的管理。还有差异更新,出现异常的监控和降级。还有性能监控。


腾讯课堂中除了有RN技术实现的页面,也有很多采用H5技术实现的页面,但是有些native能力需要同时向RN和H5提供,由于两种方案的技术差异,会造成两种提供方式,就是我们需要为h5写一套native-api,同时也为RN写一套native api。H5中的,js调用native能力的时候通过h5的bridge调用native-api, RN中则是通过rn的bridge来来源native-api,那么怎么把同一份native-api同时提供给H5和RN呢?



先看一下H5的bridge实现,我们打开一个web页面时,在开发者选项里可以看到有很多网络请求,而这些请求webview都是能拦截到的,那么我们基于这种方式来实现调用native的能力,就是js发起一个网络请求,h5bridge作为协议头,后面带有module,method这些参数,webview判断到这个请求是h5bridge协议的,就把这个请求拦截到并解析协议参数然后去调用native的api。



那么RN的bridge呢,在RN中带调用native的通道已经是有了,像UIManager.createView这些都是调用native的api,目前RN支持的参数类型有:整形,浮点型,字符串,数组,map,function,但是对function的支持有一些局限性:数组和map里面不支持function类型,function仅能在参数列表的末尾,最多两个(就是成功和失败的回调),而且function只能执行1次。



那么提供给H5和RN的接口怎么统一呢?假如js需要调用native的存储接口,js调用native时,H5调用走h5brige, RN中,我们写了个NativeBridge的RN module他,通过这个module来调用。这个NaitiveBridge的调用会转换为h5的h5bridge://Storage/get/…或者RN的NativeBridgeModule.call(“Storage”, “get”,  …),就是把模块名字,方法名字和参数传到native进行分发到对应的native-api里处理



传入一个大参数一个map, 有key和一个success的回调,这样api格式很像小程序的api, 比较直观优美。但是这种调用在原生RN上是不能支持的,因为RN的调用不能再map里嵌套函数



那么腾讯课堂怎么支持这个功能的呢?首先参数转换成:NativeModules.NativeBridge.call(“Storage”, “get”,  “[…]”),“Storage”作为模块名,get作为方法名传入,还有一个为参数列表的字符串。参数怎么转换呢?我们队参数列表进行转成json字符串,对函数类型做了特殊处理就是把function用一个自增的id替换,并把这个id和function对象关联起来,最终的调用会转化为NativeModules.NativeBridge.call("Storage", "get",  "[{"key": "key", "success": 1}]"),回调的时候只需要把funcId传回来就可以了,根据funcId就可以找到对应的function对象,然后执行。在native这个module怎么