微信扫描登录
或者
请输入您的邮件地址来登录或者创建帐号
提 交取 消
GITBOOK.CN需要您的浏览器打开cookies设置以支持登录功能

React Native在移动O2O应用中的实践

2016年3月19日,ITA1024互联网技术开放日——前端技术应用实践专场在中关村WEPAC空间盛大举办!近400位经验丰富的前端工程师共同参与,让一场技术开放日沙龙变成了前端技术的峰会大趴!

饿了么资深前端开发工程师戚岩分享的主题是:ReactNative在移动O2O应用中的实践。

如下是3.19ITA1024互联网技术开放日戚岩分享实录。

大家好,很高兴在这里跟大家交流前端开发,我今天分享的主题是ReactNative,基于我们之前在饿了么做的帮饿了么商家招聘配送员和兼职平台的IOS应用的经验,目的是帮助对ReactNative感兴趣的同学了解ReactNative目前发展的情况,还有你如果想选择ReactNative进行移动端开发,能帮你实现做到什么程度。

我叫戚岩,之前用ReactNative开发了一款IOS移动应用,饿了么北京团队是不区分终端开发和前端开发,对ReactNative感兴趣,或者安卓、IOS都可以向我们靠拢。

enter image description here

第一个问题是我一直比较关心的问题,脸谱为什么要开发ReactNative?

我认为对于一个框架持续的发展,如果没有一个脸上生长环境为它服务的话,是不能够持续发展的。其实这个问题也间接能帮我们看清楚什么类型的APP适用于ReactNative进行开发。其实ReactNative的出现并不是想替代OC无接管所有的IOS开发,比如脸谱的一款交互非常复杂的产品,就不适用于ReactNative开发,适用于业务复杂型,而不是页面复杂型。

在加入饿了么之前我一直在很多公司做广告方面的业务,广告就是一个典型的业务非常复杂,其实在广告系统中进行js开发只要写的是很复杂的业务逻辑,其实不单单像普通用户产品一样只有B端、C端,最多有管理端的比较轻量的配置。广告系统中有客服、销售、财务等等角色,会有很多内部后台的系统,其实这个进行同一种语言开发是可以大量互用代码的,如果不这样面临很困难的局面,用各种语言写的这套业务逻辑,后续想更新维护的时候,要把所有人叫到场,然后大家同步改一个东西,IOS页面限制可能会让其它端跟它很难重合,我自己觉得脸谱可能有这方面的痛点,然后开发了这样一个基于js的框架来完成各种手机APP的开发。

enter image description here

我们为什么选用ReactNative?

就是因为饿了么北京前端团队成立不久,去年刚成立,开始我们没有ReactNative工程师,这也是对很多小公司,或者是一些大公司刚成立的部门都会面临的问题,这是常见的问题。因为我们都是写Web前端工程师,对ReactNative感兴趣很久,尝试写了一个APP,实际看起来效果还是非常不错的,所以以至于我们放弃了招聘原生IOS工程师。

enter image description here

使用者进行开发的好处

这里有一个例子,业务中一个场景显示时间,这是很多应用中遇到的问题,时间显示的规则是今天发生的只显示小时分,如果今年就只现实月日小时分,如果今年以前就完整显示。做js开发会用到很多第三方npm库,日期我们也用了著名的库叫moment,我认为如果H5或者内部管理系统,或者是安卓、IOS都采用一种语言开发的话,带来最大好处是可以共享。代码角度我更看重怎么样互用组件。

我没有做过IOS、安卓开发,估计他们会有各自自己的通用日期组件,其实学习起来的成本,如果你想用原生语言写,其实写一门语言非常快,但是要掌握它背后很多可用的一些开源的组件框架,其实这个切换成本非常高,所以我认为用统一语言做移动端开发是有好处。

enter image description here

用React Native进行IOS开发好处

IOS有版本审核的问题,通常最快一个版本需要两周时间。ReactNative开发出来的APP会分成两部分,主要进行页面渲染的由React写的js代码打包成一个文件,目前有以下几种开放的平台,我们现在项目中使用的是codepush,apphub也用过,是收费版本,对使用人数日活用户量和打包文件大小都有限制,限制是比较大的。最后exponent实现了作为ipe的功能,可以在XPD上面进行ReactNative开发。还有就是A/B test,小流量开发是Web开发经常用的手段。客户端开发更新版本的自身的问题,如果之前不用React Native一些可以发布的框架,进行A/B test只能在客户端写死一个算法,这样是不能够远程控制的。

enter image description here

ReactNative目前的一些问题

ReactNative目前是一个还在beta状态,对自己的版本定义还在零点几的水平,我们这个APP开发经历版本是0.14到0.22,基本上在每两周发布一个版本,更新速度非常之快,在这样的情况下难免会存在这样的问题,就是会有很多已知的性能的问题不能改善的,只能改善一些比较重要的问题。还有很多开发者比较关心的问题,开源社区的问题,这个问题之前用过React 开发Web的同学知道,现在发现基本常用移动端组件都已经能够找到比较好的开源的使用。其实移动开发跟PC不太一样的点组件并没有那么多,我们发现自己写起来也不是很困难,因为受制于屏幕大小的影响,组件并没有特别复杂。

最后提到一点文档已经完全跟不上版本升级的速度,升级过程中没有办法同步维护文档,以至于很多时候我们进行ReactNative开发不得不看它的源码,才能知道新开放的是什么情况。

enter image description here

介绍一下ReactNative工作的基本原理

ReactNative是一个集成的作品,在此之前脸谱已经在oct端做了页面布局,可能在React这段有自己的结构,切换到ReactNative就做了接口的调用,实现的是RCTbridge,通过暴露给js的方法,分发到N Method当中,最后跑到手机上都是由原生代码实现的交互。

enter image description here

下面就是ReactNative的一些组件对应的就是原生IOS中UIP的组建,因为它虽然实现了一套类似于CSS的一种页面布局方式,但是这种方式其实并不是真正的CSS,它其实还是一种通过组件参数声明方式进行设置,所以它实现的这一套基于核膜型布局方式,每一个样式组件都绑定到每一个标签上的,不能像HTML的CSS可以把任何属性写到任何DOM结构上。

enter image description here

我会具体介绍一下我们在这款APP开发中需要开发的一些,对其它APP也会同样适用的组件的使用情况,这个APP是帮饿了么商家招聘配送员、兼职的平台,初期我们能用React Native进行,刚开始算是试验形式的,取决于在业务上使用场景主要以安卓为主,因为它的受众安卓用户占主要,项目临启动期间引入只有饿了么商家兼职任务,但是未来可能会考虑放入更多兼职的时候,IOS用户会越来越多起来。这个项目现在不叫有时了,启动的时候叫有时。

enter image description here

下面是我介绍的组件。Navigator是移动开发中最重要的组件,它在ReactNative有两个组件,我们初期想选用安卓和IOS通用的组件,但是发现它有动画效果不流畅,它在跨屏会做之前页面缩小的转换,这在操作的时候会感觉页面卡,基于这个特点我们就放弃了Navigator,转用NavigatorIOS。NavigatorIOS有好的一面,自然有坏的一面,AP比并没有Navigator丰富,NavigatorIOS是因为大家发现Navigator不好用,模仿它的API写的,但是并没有完整实现它的所有功能,导致我们使用中发现它并不支持从底部向上滑出新的页面,这个时候我们就在所有需要底部滑出的页面之后再进行其它的路由的操作,又分装了新的路由。Navigator实现的路由是通过TOP和PUSH方式,从跟目录,初始页面开始,可以路由出很多条分支,整体是梳形结构。可以实现从一个节点一直跨级PUSH,它只有在叶子节点的时候才能够实现不用PUSH,它在树中间节点不能被替换的。我们分装从下往上实现的Navigator,只是做了没有提供更多功能,只是用动画实现了从右侧向左侧滑入的效果,然后数据结构上采用的是双向链表的结构,只记录了之前之后页面是什么样的关系,实现了相对简单的效果。

enter image description here

下面是一个动画,我们在进行列表选择的时候会有屏幕向上放滑下来的筛选条件,最开始的时候我们选用了ReactNativeAnimation,一步加载很多的时候会发现动画效果比较卡,卡的话还不如用H5实现。还有一个LayoutAnimation,只能实现官方文档建议描述实现一次性的动画,所谓一次性动画就是指动画中途不会被取消掉,不会被进行连续不同的变化,对于展示型的APP,大多数需求都用LA是可以实现的,有这三种配置进行动画的过程转换。

enter image description here

下一个进行移动开发都会遇到的组件叫PullToRefresh,升级到0.18版之后就用了自带的效果。但是只有PullToRefresh还达不到我们需求,通常这样一个列表会要求下拉翻页,上拉刷新,还有查询结构的展示。这里面主要讲的是ActivityIndicatorIOS,根据业务情况不同会让它有选择展示的位置,比如这个地方如果是上拉刷新,由上拉的时候已经出现了Indicator,所以就不能展示。

enter image description here

下一个是前端开发非常熟悉的弹窗,ReactNative自带了Modal,它本身也是支持动画,可以从底部滑入,没登录想报名或者需要登录的时候,会从底部滑上来,它是全屏覆盖的,没有办法控制弹窗大小和位置,不能满足所有APP需求,然后我们分装了基于ReactNative的Modal,可以自定于弹窗内容是什么,位置在哪里。

enter image description here

这也是一个IOS开发常见的东西,IOS键盘上并没有收回的按纽,我们很多页面进行操作需要收起键盘,或者是一些提示信息如果没有键盘会在页面下面展示,但是有了键盘展示到下面会被盖住,所以需要有这样,它是侦听了键盘出现和收回的事件,我们重置一下提示的位置。还有就是ReactNative自己的组件,它在ReactNative点了其中一个上流,其它都不会触发的。只有点了另一个触发,才会有反应。最开始试图解决这个问题,用了Scrollvicw,用的时候发现并不是很完美,因为用它会在失去焦点的时候,第一次触发屏幕会失去焦点,收起键盘,但是并不能够点击一次就切换到下一个输入项。所以最后经过各种试验,找到了一个方法,用ReactNative提供的组件把整个弹性的容器包装起来,然后主动收起键盘,也不会影响输入项目。

enter image description here

下一个就是进行ReactNative开发和Web开发最主要的就是能做到更精确的操作,比如Swipeout,原理就是基于ReactNativeAPI分装的Panresponder,事件周期跟H5区别处理响应更丰富,在H5中只有几种方法,但在ReactNative是基于原生分装,可以精确显示到触发想要操作容器的时候,可以通过触摸触发,也可以通过滑动触发,触发之后立刻显示到这个方法,拖拽就是这样的过程。其它几个API实现的事情,在ReactNative中,在全局之能同时有一个onrespondre工作,前一个panresponder运行周期中没有办法执行后一个。但是如果可以被中断,就会执行REJECT方法,另一个就可以进行新的执行。在实践还不足以让它跟H5产生多大的差别,它相比H5还有一点,除了返回事件东西,这会增加额外几个属性,我们在Web没有见过的,比如S轴到Y轴移动的距离,比如S轴Y轴的速度,可以帮助我们做更复杂的进行手势操作。

项目中的依赖

这是很多同类型应用都会面临的一个问题,当我们不想要写原生OS代码情况下,怎么能让我们APP实现绝大部分的需求。当然了,ReactNative只是一个容器,或者只实现了桥接的方式,我们可以实现拓展ReactNative,实现各种原生功能,只要你想暴露给js都可以,或者你想原生代码在APP里实现也可以,我这里介绍一下我们项目中的Web依赖。

enter image description here

首先codepush,托管文件的单独云平台,这是微软开发的,当时换到这个觉得是微软不会轻易倒闭,我们担心自己代码托管第三方,不排除未来自己会开发自己的代码托管平台。我觉得国内很多人力富裕的BAT完全自己可以开发一套帮助移动端开发托管js代码的云平台,之前很多IOS开发不同程度接入了js代码,实现热更新。codepush三个方面,可以把单独文件发到一个环境中,还有同步不版本,还有支持回退任意版本。可以控制最小化轮巡的时间,自定义检查一遍有没有新的包,然后可以设置你是在这次使用中应用内更新你的单独文件,还是用户下一次打开APP更新,通常一般会做下一次打开更新,因为在用户操作过程中突然整个页面都变了是比较奇怪的事情。还有它可以配置一个升级的提醒,可以告诉你我们有了一次更新,因为它本来就是经过升级,很多时候还会有这样的通知办法。

enter image description here

我们用的第三方开源组件进行图片上传,这个APP对图片上传需求量不是特别大,只是用户头像和身份证校验,所以用了IMAGEPICKER,类似于原生,会弹出一个头是摄像头拍照或者读本地相册,授权就可以进行了。比较重要的配置参数是当你做文件大小的限制,还有质量度的限制。但是这个东西不够灵活的一点在于它没有办法根据你的图片大小本身做剪裁,比如传了本来已经很小的图,不需要再把这张图拼得很低,但是用了这个只能一刀切,现在还没有实现的,我们也向移动框架总部提了需求,让他们做可以剪裁,可以帮我们做事情,自定义根据图片文件的大小进行重新的配置。另一个是之前用到的DashBorder,0.18版ReactNative已经自己支持了这个,所以就去掉了。在进行ReactNative开发的时候,很有很大力气写的东西,引用第三方的东西,在新版本中就已经支持了,这个不见得是一件坏事。

enter image description here

因为这是基于地理位置的服务,所以用了第三方Location和geocoder,它还实现了很多,跟HTML一样的东西,还是比较强大的。但是这个东西还不能满足需求,因为我们要把经纬度转成具体的城市或者具体的信息,用了第三方的插件。除此之外,我们并不能满足于在程序使用期间获取地理位置的需求,我们用了一个服务进行后台拿到用户授权,目的兼职进行服务的时候,我们要进行定时向后端上报地理位置。

enter image description here

这是更加常见的需求,我们进行移动端开发都会用到开放第三方ID登录或者分享,初期用了openshare。但是微信和QQ分享的时候实现是有差别的,微信要两次才能拿到用户ID。之所以这个插件觉得不够用的原因在于用户手机上没有安装微信和QQ的时候,这个插件就不能够触发,后来我们换了一个更加好的shareSDK,实现的如果没有安装微信,就第三方网页进行登录。

enter image description here

后面是接入分析统计叫talkingdata,它只提供了IOSICDK,其实对于React开发,自己身份周期是比较固定的,要检查配置是比较容易的。还有一些点击操作可以检测事件。统计可能是移动开发必须要接触的一个东西,我们目前是用了这个服务。

enter image description here

Redux,它最近一年非常火,是基于Flux原理实现的简化版,对于复杂业务系统前端开发来说,之前别垢病了很久的方式是比好的,直接修改modle,业务复杂方案难以维护。演进到REDUX模式的时候,认为已经是必备的方式了,它更简单的一点是只有单一的STORE,只通过命令空间区分。

enter image description here

之前遇到的一些坑

首先设备适配问题,浏览器适配,是我们一直要面对的事情。进行IOS开发,感觉这个事问题会变得少一点,因为都是在IOS系统中,第一个问题是我们在IOS5测出来的,但实际上IOS8,解析ES6语法的时候是分步支持的,所以我们之前用for…of做循环出了问题。ReactNative的开发过程是跟Web开发过程相近的,也可以断点,报错信息也会比较固定。但是我们发现进行IOS开发js出错是有些问题很难解决的,比如这个问题会引起程序崩溃,我们也是用了IOS一个东西去看,出现了这个异常。ReactNative开发之所以能够比IOS原生开发提升效率很大一步原因在于出错更容易定位问题,IOS之前遇到问题都花了很长时间才找到问题的原因是什么。6Plus遇到的边框问题,像素密度不同造成的,ReactNative提供的像素比例的API,可以根据不同的设备取不同的值,按照我们惯性思维可以定义所有设备中表现一致的,但是在移动开发中并不是这样的。

enter image description here

之前遇到的问题,耗费时间比较多的是升级ReactNative版本,之前我们开发中经历了0.14到0.22,并没有每个版本都升级,但是会有很多时候用到新版本的特性,不得不进行升级。升级的过程中每次都比较痛苦,经常跑不起来,原因可能也比较复杂,有可能跟nodenpi环境有关系,ReactNative自己的版本也不够稳定,之前遇到两个比较难解决的ReactNative自己依赖的包的支持是不一样的。还有之前遇到过用page进行搭配的时候,在模拟器上打包不成功,要手工改代码。如果升级之后重新用appstore每次要手工改代码。

还有listview,体现在如果不进行初始化配置设置的话,会优先只展示两条,会感觉数据是一点一点累计起来的,解决这个问题设置了一个比较大的pagesize,看起来是一次响应的。

enter image description here

接下来需要做的事

分析这个事情,现在并不确定,我们可能会介入饿了么公司内部统计平台,可能能实现更可定制化的统计,是不是能够提供React Native的版本还不太确定,所以这个事情是待定的。

关于React NativeFETCH,如果想要在这个做TIMEOUT,目前需要管理每一个请求。未来可能会做小流量的测试,还有可能通过位置接入高德地图,我们现在有一个产品需求要在APP中显示公交线路的展示,这是用React Native地图API不能满足公交查询的,可能会需要引入高德地图,当然这个没有想好是H5,是Web6,还是原生方式,这个事情还没有定论。

谢谢。

————Q&A————

提问:有几个问题想问一下,之前提到code?

戚岩:不只做代码的托管,还能提供IDE,进行IOS开发的时候CODE非常重,提供了写代码的环境,我们没有用。

提问:LISTVIEW第二个说到pogesize,IOS开发刷新肯定数组会很大,不会就是100兆,几千都有可能,这种怎么做?

戚岩:分装,React Native包装到了6里面,多数地方用了分页方式加载数据,只有少数不确定,没有分页接口用的。

提问:现在还是没有用到?

戚岩:是。

提问:第三个问题发包的时候,平常React Native会影响多大?

戚岩:我们现在包不到1兆,几百K。

提问:关于安全性问题,我们写的代码构造界面代码都在里面,再比如写业务逻辑,采用第三方登录,如果全部用React Native写的话,安全性问题怎么解决?

戚岩:关于渲染页面js代码没有必要刻意隐藏,我们做Web前端也遇到这个问题,并不是什么需要不对外公开的东西。关于你说的P,React Native开发好处就是可以放到OC端,不在js那端做。我觉得一般的东西并不重要,因为我们这个APP也做了安全性的东西,最新版本做了银行卡绑定提现,做了rsa,传统Web方式做事情就可以了,没有体现出跟Web不同的点,现在反而多了一种选择,可以暴露的放在js里做。每次只询问有没有新的包,并不会下载,如果包一直没有变,是不会下载,包是存在本地。

提问:现在React Native适合开发哪些应用,您前面讲的是业务复杂型,能更详细一些吗?

戚岩:不知道你做没做过业务复杂型应用,我刚开始举的例子,广告系统这样的应用,前端开发复杂度主要体现在,广告系统是类似于管理平台,页面之间交互比较类似,但是通过广告主余额,投放广告地域,时段,进行复杂的操作都是业务代码,跟应用层并没有直观关系。

提问:在现有APP上用React Native来开发合适吗?

戚岩:饿了么我们现在了解情况就是有配送员用的一个,两个页面,一个是等级,一个是通知,用的React Native,我了解之前也听过一些人分享,可能都只是对已经存在的项目,在部分页面采用,因为我们这个项目是全新的项目,所以才能整体使用,整体和部分都是可以的,可选的。