阅读 2749

跨端跨栈连载 1/7:RN 开发 8 个 APP

下期预告

前端早早聊大会目标成为用得上、听得懂、抄得走的技术大会,计划 2020 年办 >= 15 期,由前端早早聊与掘金联合举办,前端早早聊大会行程动态、录播视频/PPT/讲稿资料下载请关注 「前端早早聊」 公众号跟进。

你的支持,是早早聊办下去的唯一动力!

还想听哪方面的分享,直接加 Scott 微信: codingdreamer 提需求吧!


第十三届|前端搞构建专场,8-15 即将直播,9 位讲师(宋小菜|百度|政采云|腾讯|天猫精灵|蚂蚁|淘宝),👉报名地址


本文是第九届 - 在线文档,前端早早聊第 62 场,来自宋小菜大前端负责人 - 刘芳的分享讲稿简要整理版(完整版含演示请看录播视频和 PPT):


大家好,我叫刘芳,是宋小菜大前端的负责人,这次演讲的题目是 toB 场景 8 个 APP 的 RN 最佳实践。

为什么选择 React Native 技术栈

第一部分的问题是宋小菜现在有 8 款 APP ,为什么我们选择了 React Native 技术栈?

公司介绍

首先宋小菜是一家卖菜的公司,他的愿景是做开放创新的数字化生鲜产业服务平台。

公司目前触及到的业务主要是生鲜领域的整个供应链,包括上游和下游。

宋小菜从 2015 年成立至今,已经开发了 8 个独立 APP,这 8 个 APP 加起来有一两千的页面数量,它们服务了下游 3 万多城市端用户,上游 1 万多供应商用户,还有连接上下游的 7000 多司机用户。当前宋小菜每年的交易吨位有 30 多万,这样一个体量的公司,我们可以看一下它主要的业务:

业务介绍

我们对接的上游用户主要是蔬菜的供货商和蔬菜的囤货商,下游用户是蔬菜的批发商和中小菜贩,中间是物流司机。

那么一家创业公司为什么有 8 个 APP ?主要是因为 8 个 APP 它的目标用户是完全不一样的。

上游的蔬菜基地的用户主要是Daiban,囤货商还有供应商,这是我们的外部用户。他们的核心诉求是:他们的菜能不能卖出去?怎么卖?多少钱卖?一天能卖多少?

在上游有也有内部用户,即公司自己的采购团队。采购团队关心的是我要采购的商品种类,商品品质,还有我每天需要采购的数量等等。

从上游的蔬菜基地到下游的批发市场,还有我们的物流团队,物流团队关心的是什么呢?关心的是每天他有没有东西要送?他需要开什么样子的车?从哪里送到哪里?什么时间送?

下游的用户就是我刚说的蔬菜批发商,包括了二批老板和中小菜贩。这些人他关心的是什么?他关心的是宋小菜有什么样的菜?这些菜有多少钱?质量好不好?服务好不好等等。

服务这些的蔬菜批发商和中小菜贩的有我们的销售团队,销售团队关心的是每天的他的用户有多少,他们要什么样的菜,菜的价格是多少,销售团队每天能赚多少钱,能不能达到我们的 KPI。

这样复杂的用户群和场景就决定了宋小菜的 APP 针对的目标用户是非常不一样的,用户的需求也是不一样的。只有针对不同的用户需求提供独立的产品才能满足公司的业务发展。

前端介绍

下面我们看一下宋小菜现在前端开发资源的情况。宋小菜整个大前端只有 15 个同学,这15个同学对接了 8 个 RN APP,十几个 H5项目(这些 H5 有分微信端的 H5 和钉钉端的 H5,钉钉端的 H5 面向公司内部用户,做一些协同的东西。微信端的 H5 面向外部用户,提供的下单相关的需求)。

除了 RN App 和 H5 之外,我们还有 6 个小程序,20 多个 PC 端的项目。此外,我们前端还有自己的多个基建平台。15 个同学针对这么多的端这么多的项目,我们怎么样去选择我们的 APP 的技术栈,我们觉得适合当前当下资源和场景的才是最好的!

作为一个才成立 5 年的公司,它的产品也是在不断的变化当中的,可能前两年做的产品,两年后就完全换成另一种打法和业务方式,之前做的产品功能不久就会变化,而我们的前端开发资源其实又是很少的,目前只有 15 个。所以我们非常追求开发效率和质量,需要 App 能够快速迭代,快速的帮助业务同学进行试错。

盘点一下宋小菜这 15 个同学的技术栈,我们发现其实这 15 个同学最擅长的是 React、Node.js。此外,还有两三个同学以前做过 Java、或者安卓、 或者 IOS,具有一定的 App 原生开发能力的。还有一些同学有 Vue 的开发背景。

基于研发成本、研发效率和用户体验的综合考量,我们认为我们不做混合型的 Hybrid H5 开发而做 RN 开发,一方面是追求 APP 相对比较好的体验,另外一方面,也追求我们的开发效率。我们不用原生开发,也不用 Flutter 开发,虽然可能原生开发和 Flutter 的性能和体验更好,但是如果投入很多的资源到原生和 Flutter ,对我们这 15 个同学来说,它不是一个很具有性价比的技术方案。团队不需要招那么多的原生工程师,团队同学的技术栈也不会割裂,所以让 React 的同学既做 RN 又做 H5 和 PC 端,是当下宋小菜前端的一个最佳的方案。

React Native 基础建设

第二部分主要说下我们现在 React Native 基础设施方面的探索。

React Native 基础建设概览

首先看一下我们的 React Native 基础设施概览。

这张图其实不仅可以套用到 RN 技术栈,任何一个技术栈都可以从左边的几个层次来考量,最上面的三层分别是代码规范,工程结构规范和 UI 组件规范。这是任何一个技术栈最核心的东西,我们有了团队内部比较好的代码规范和工程框架,在工程框架之上我们去建设我们丰富的组件库。这里针对 RN 我们既有基于 UI 的展示型组件,也有需要原生能力的 Native 的组件。

除了上面的三个层次之外, RN App 还需要建设它的打包和发布平台。打包平台后面会详细的介绍,我们团队自主研发了一个叫做“大伯伯”的打包平台,它是基于分支/平台/环境管理的打包平台。针对 RN 发布,我们研发了一个可以进行原生发布/热更新发布/白名单发布的平台,这个平台还可以对历史发布进行管理,我们内部叫做“大表姐”发布平台。

在大伯伯打包和大表姐发布平台之上,我们对接了宋小菜技术部的 DevOps 工作台,DevOps 工作台是针对整个宋小菜技术部的,从需求开始阶段到 UI 设计、技术研发和产品测试,包括迭代管理、Bug 管理、一键发布等功能,涵盖了整个的研发流程,我们前端的打包平台大伯伯和前端的发布平台大表姐,也对接到了 DevOps ,可以在 DevOps 上进行需求迭代的配置性后,完成 App 的一键打包发布。

除了编码、打包和发布外,我们需要知道产品上了线之后的线上表现是如何的。早早聊之前的分享,也有我们宋小菜的小哥哥分享了我们的大浪子监控,我这边只是提一下我们 APP 端是如何接入大浪子监控的。有了监控之后,还需要使用监控产生的数据做一些报表型。当然我们的报表型组件可以展示任意数据源的数据,不仅仅是监控数据,也有比如说销售团队的销售状况,或者用户状况等。我们在我们的 RN APP 上沉淀了通用的报表展现的解决方案。

说了这么多,我不知道大家对 RN 技术栈有怎样的了解程度,首先就先讲一下 React Native 的基础技术架构。

React Native 技术架构

React Native 从上到下可以分三层,最上面这一层,作为前端开发是经常会接触到的,就是我们的 JS 层。JS 层包含了官方原生提供的核心 Components 和核心 API,还有针对我们 RN 布局的 flex,还有一些社区的三方模块,在 JS 这一层。上面橙色的主要是我们做业务开发的一些写的 RN Components 组件。

中间这一层是关联 JS 层和原生层非常重要的一层,我们称之为 JS Bridge。这是 JS 层调用原生 API,调用原生组件进行页面渲染非常重要的一层。安卓端这一层主要是 JavaScriptCore,也有使用 Facebook 自研的 hermes的,在 IOS 端主要是用 JavaScriptCore,我们 RN 中间层可以比喻成 JS 和 Native 之间的通讯员。

底层就是安卓和 IOS 的原生层,IOS 和安卓原生层是上层 JS 核心 Components 和 API 在底层的封装,原生层上有一层叫 yoga 层,yoga 层是 Facebook 自研的跨平台 flex 引擎,用于解析和渲染 flex box 的。

我们做 RN 开发,如果涉及到原生的特殊需求,比如说我们最近做的蓝牙打印,还有之前做的微信、支付宝原生方法的封装,这个时候我们就会接触到原生层,做一些原生层的封装。

React Native 脚手架 - Brick

了解了 React Native 的技术架构之后,再来看一下我们的 Brick 框架。

Brick 框架包含了我们 RN App 的工程脚手架和工程模版,在上图蓝色的圈圈内部白色的圈层就是我们 Brick 框架所做的事情。它规定了统一基础的依赖包,包括了 RN、 IOS 和 安卓的一些基础依赖的版本,比如说我们现在 RN 用的是 0.59.9 这个版本,那么对应的安卓和 IOS 也有确定的基础版本。

除了基础依赖包之外,我们还有脚本工具,脚本工具会做一些命令化的功能,比如说环境切换,热更新配置,还有代码规范检测等等。

除了脚本工具和基础依赖之外,Brick 框架还封装了通用的页面模板,比如宋小菜有统一的登录和网关,这个流程统一规范化的,我们就把登录和网关的东西封装到工程模板里面,让业务开发不用关心登录和网关的东西,只关注业务的核心流程的代码实现就可以了。

针对 RN 的全局状态管理,我们约定可以选用 rematch,这个后面也会大概讲一下。

除了这些 Brick 框架自有的东西之外,还有前端跨平台的工程在 RN App 中的嵌入。比如 RN 更新检测的 SDK、RN App 埋点的 SDK,以及 RN 侧的报表展示插件,后面都会详细的去介绍一下。

这里对 RN APP 工程框架 Brick,再来回顾一下刚刚说的几个点:

  1. 我们在 RN 脚手架里面统一了基础的依赖包,并按照一定的规律去升级。升级的时候,也可以对相关的三方包的依赖版本进行检测。

  2. 脚本工具目前我们主要做的是环境切换、热更新配置,本机打包以及处理一些 IOS 证书 PP 文件管理等,以及代码规范检测。

  3. 组件库这里有展示型的基础组件:包括多套主题,Button、Text、TextInput、Page、Upload 等。还有原生组件,原生组件有很多是按需引用的,比如说微信三方的 wechat 原生组件、支付宝的 Alipay,还有我们蓝牙打印的 bluetooth 等等

  4. 除了组件之外,我们封装了基础的工程模板,模版中封装了路由,我们是基于 react-navigation@3.+ 的版本,在这个模板之上提供了统一的登录和网关请求等功能。我们还提供了路由的定制和登入登出场景的切换,比如说在什么情况下可以去触发它的登入登出。

  5. 还有我们在 RN 上面会用到全局状态管理,全局状态管理我们现在用的 rematch , 它非常类似于 dva ,但是它是使用 async/await 处理异步请求,对于习惯了 promise 的开发者,rematch 更易于接受和使用。同时我们还在rematch 之上还使用了它的一些三方插件,比如 loading 和 persist 等。

  6. 除了全局状态管理,还有宋小菜跨平台的一些组件在 RN 上的接入,比如说内置了的更新检测和更新功能的组件,埋点上报组件,报表组件等

脚本工具

详细讲一下我们的宋小菜的脚本工具做了什么事情。

脚本工具它一方面是因为我们 APP 开发肯定会有多套环境切换,它可以使用脚本就非常方便的去切换环境,还可以去执行我们的热更新的一些配置,我们使用了 fastlane 为核心的可以配置打包命令 IOS 证书 PP 文件管理,还有我们的 IOS APPStore 的一些信息管理

在这个之上,我们还可以定期的使用脚本进行整个框架的一个升级。在代码提交的时候进行代码检测,我们现在的代码规范主要是使用的是 standard,还有一些其他的命令,比如说我们进行 AndroidX 的一个切换等等。

APP 组件库

这个组件库包括了基础的 UI 组件,还有一些功能性的组件,这些功能性的组件有很多是原生性的,提供原生开发能力的,那么我们现在 UI 组件大概有 40 多个,在我们刚刚说过的宋小菜的 8 款 APP 里面,使用覆盖率已经达到了 100%,页面上面的东西基本上都是用组件进行搭建的。

我们功能型原生组件就包括刚刚说过的微信支付宝,还有 message-box,蓝牙,然后还有报表,埋点等使用原生开发能力的组件。

上图是我们的 RN 组件文档,可以看到它的分类,它就是会有基础组件数据展示型的、数据录入型的、时间类的、交互类的、通用页面的,还有其他的。下面这张 PPT 大致列举了一些组件。

讲过了我们的 RN 框架 Brick 和组件库后,我们看一下 RN APP 比较重要的打包和发布的平台。先看一下我们大伯伯打包平台长的是什么样子。

大伯伯打包平台

在打包平台上对任何一个 App,有该 App 的概述和打包需要的配置操作,那么打包就只要在上面选择打包的分支、打包的环境、包的类型(IOS 包或者安卓包)等等配置就好了。

确认配置后点击“极速打包”,就会等待打包结果,所有成功的包都会生成一个下载用的二维码,无论是测试还是开发,它只要扫一下这个二维码,就可以去下载我们已经打好的包,验证这个包的功能。 这个打包平台它是用 Node.js 开发的,它的主要功能包括:打包流程的控制 和 安装包的管理。最近打过的包在上面都会有历史记录,需要使用的时候,只要扫一下二维码就可以下载使用。

我们的打包是以 Jenkins 为核心的一个打包任务管理,它与发布平台进行了整合,它形成了前端 APP 打包发布流程一体化,并且它与公司的 DevOps 平台也进行了整合,形成了开发流程的一个闭环。

大表姐发布平台

上面是我们的大表姐发布平台,发布平台有很多功能,我截取了其中的发布版本列表。这里记录了每次发布的 App 是什么,发布的是什么平台,什么分支。每次发布的版本号,发布渠道,还有发布文案等等。

App 的安装页面也是提供给对外下载的页面,该页面会检测手机端的平台是 IOS 端还是安卓端,然后提供下载包。

我们的发布平台也是使用 Node.js 进行开发的,他在 RN 应用方面有下面这些功能:

  1. 提供了热更新的分发功能,它可以按照渠道分发,它可以便于测试,比如说它可以只分发 IOS 端或者只分发安卓端,在热更新方面,它是提供的是增量更新,它可以节省用户的的网络资源请求。

  2. 除了热更新发布之外,可以提供原生安装包的一个分发功能,实现了按渠道分发,便于测试

  3. 同时它提供了一个自动化的版本管理方式,避免开发者在项目中修改版本号。其实我们刚刚打包的时候,如果我们打的是正式的包,就可以选择这是怎样的迭代?比如说是大版本更新还是功能迭代,还是 hotfix。确定了之后在发布的时候就会自动地更新版本号,发布完成后还会把更新之后的版本回写到 git 仓库。发布时候还有一个强制更新选项,如果选择是强制更新的话,那么用户点开 APP 就会有个强制更新的弹窗,这时候用户只能去更新才能使用。如果是非强制更新的话,用户就可选更新了。此外,我们还有基于渠道和灰度的开关的设置,支持线上进行版本回滚。每一次的 App 版本发布之后,都会记录这个版本,如果线上发现了重大问题需要回滚的时候,就会触发回滚操作,就把这个版本取消掉。

  4. 同时我们也会对需要更新的安装包进行检测,只有是通过我们小菜的发布平台分发出去的,才能通过我们的安装包检验。防止外部安装包伪造,提高了我们发布的安全性。

  5. 我们也有针对每个版本安装情况的统计,比如说我们 1.0 版本,发布了 1.1 版本,那么每个版本它安装的用户是多少呢?我们可以实时查看 App 最新版本的安装情况

  6. 我们发布平台也是集成在公司的 DevOps 系统上面,然后形成了前端流程的一个 CICD 闭环。

后面这个图会详细的介绍了一下,我们这个打包发布是怎么样的一个流程,可以跟着我从最开始看一下。 最开始的时候是用户既可以在 DevOps 上面进行点击发布,也可以在我们的大伯伯平台上面点击打包,打包命令其实就是调用了 Jenkins,Jenkins 调用 fastlane 命令进行打包,打包了之后,就会生成对应的包,IOS 包它生成了 ipa 文件,安卓包生成的是 apk 。然后会把打包结果进行一个上传,并通知我们的打包平台(DevOps 或者大伯伯),接着就判断当前的包是否是发布包,如果不是发布包打包流程就结束了。

如果是发布包的话,发布平台就会自动的去生成一个预发布单,然后预发布单就会去判断这个包是对外的 AppStore 包,还是我们企业应用的包,如果是对外的 AppStore 的包,就会自动的去把包上传到 AppStore,并调用 AppStore 的 API,去填写提交审核的发布单,然后就直接生成了审核单,等待 AppStore 的审核结果,如果 AppStore 审核通过了之后,我们发布流程就结束了,如果 AppStore 审核拒绝的话,那么开发再看看不成功的原因是什么。

从这幅图可以看到,其实开发人员在做 App 发布的操作非常简单,就是最开始绿色的流程。他只要在打包平台上或者 DevOps 平台上面,配置好参数点击发布,后面的所有的流程都是自动化去实现的。

讲过了打包和发布之后,再讲一下针对 App 的线上表现,我们实现的一个全平台的监控平台,它叫大浪子监控平台。

大浪子监控平台

因为前面已经有我们宋小菜的开发小哥哥分享过这一块内容,这里就简单看看功能。

第一幅图就是我们去监测目前线上 APP 有没有什么异常 Issue?每个 Issue 的等级是什么?这里等级的划分是我们基于一些算法来算出来的,从 P0 到 P6,其中 P0 级是最严重的,那最不重要的是 P6 级的。

每个 Issue 当前的状态是什么?每个 Issue 的错误类型和错误信息描述是什么?这个 Issue 是出现在 JS 端,还是 Native 端等等。

点击一下它的最右侧的详情,我们可以去看到它具体到底是什么样子的一个问题,下面会有对 issue 的一些详细的错误,比如错误栈、最近一段时间内的触发频率等。

基于这个 issue 我们还可以设置一定的报警规则。

在每个 Issue 里面其实我们还上报了 session 信息,使用这个 session 信息,就可以追踪关于这个 session 的整个的事件的一个流程是什么样子的?比如说 session 最开始的可能就是用户打开了 App,接着就进入了某个页面,请求了哪些接口,然后他做什么样动作,然后又一个路由切换,又是网络请求等。同时在这个 session 里面我们还知道这个用户的设备型号和用户信息等。

最后这幅图是说我们可以针对 issue 会制定预警规则,使用预警规则在一段时间之内去观察这个 Issue 有没有命中这个预警规则。因为之前有我们的开发者已经讲过大浪子的东西了,我这里只是大概的罗列了一下它的功能。

然后监控平台它是一个多平台的埋点监控,我们 RN 只是它其中的端,针对 RN 我们在最开始的图上面,我们也写了我们在 RN 上面有一个监控的 SDK,这个 SDK 其实是可以捕获我们原生端和 JS 端的错误,然后进行上报的,而且在大浪子上面我们可以对上报的错误进行管理和定责,也可以去追踪它错误具体发生的问题是什么,它是如何被触发的,并且对这个错误我们可以进行一定的报警,一旦认为我们这个错误已经被解决了,我们可以制定一定的报警规则,然后多长时间去检测一次他这个错误有没有再次被触发这样子一个报警。然后讲过了监控之外,我们还有另外一个针对APP端很重要的一个平台,就是我们的数据报表,先看一下我们移动端的数据报表是怎么做的。

数据报表

我们有一个叫大盘子的一个平台,这个平台主要是公司的 BI 和数仓同学使用的。在这上面,他可以选择数仓里的某一个数据表,然后指定他这个报表的 X 轴的维度是什么,Y 轴的指标是什么。

我们在左侧可以对这个表的展现进行定义,比如说我们用的是柱状图,还是波线图,或者是地图之类的。定义了之后,还有比较详细的 X 轴和 Y 轴的字段定义,通过这些配置化的定义之后,就可以生成我们在 APP 上面可以看到的数据报表。我们可以做很多看板,每一个看板里面可以是一个地图,也可以是一个混合了表格和各种的柱状图线图的复杂报表,这些看板就可以在移动端使用。 这张图大概的讲了一下我们报表的东西是怎么样实现的。

前面的数据准备工作是公司的数仓的人去做的一些工作,他们把业务数据清洗到数据仓库里面,数据进入数据仓库之后,就可以在我们刚刚的平台上进行 PC 端的拖拽制图,图做好生成看板,这些看板最终可以进行多端展现。因为我们后面做数据报表的小哥哥也会分享这里可视化的东西,所以我就不再赘述了。

好了,然后最后我们在回顾一下我们 RN 方面的基础建设:

我们重新回顾一下:左侧的上面三层是代码规范,工程规范,组件规范,在我们宋小菜主要是使用了 Brick 框架和 CUI 组件,Native 组件进行实现。这三层我们主要的目的就是实现 RN 开发框架、开发规范和组件库,最终用来提高 RN 的研发效率。

中间的两层是打包和发布,我们在宋小菜其实有三个平台:技术部公用的 DevOps,我们前端的大伯伯打包平台和大表姐发布平台。这两层所做的目的就是提供一站式的打包和发布。它可以节省我们的 APP 端研发效率,并且保证它的流程规范。

最后下面两层就是我们做的进一步的建设性的东西,第一点是埋点监控和 Bug 预警,它的作用是跟踪了线上缺陷,并且可以监控用户行为。最后一点就是我们的数据报表,在我们宋小菜它包含了大表哥报表,和大盘子图表。

这里整个的技术部分就介绍完了,最后我们来展望一下未来。

展望未来

我们目前在 RN 方面的持续建设,我大致分了这样几点

  1. 最基础的还是组件,我们其实还是会继续的去基于我们 UI 组件和 Native 组件做一些基于业务场景的组件。其实业务场景的组件再往上可能就是一些模板性的东西,比如说是营销类的、采购类的场景组件。然后我们还会持续的扩充我们的硬件能力,利用我们的原生开发的能力,继续的扩充我们的 Native 端的硬件能力。

  2. 在组件之上,会对我们的 Brick 框架进行框架升级的自动化,因为我们现在的框架升级还是偏人工的,后面我们可以把这个框架升级做成自动化的,比如用一个脚本就去进行一个整个 APP 端的一个框架升级。再往后可能可以支持业务分包,比如说在一个 APP 里面,根据业务功能不同达成多个 JS bundle 包,有了这个功能就可以进行分包发布,最后再考虑是不是可以整合现有应用减少应用数量。

  3. 第三点就是持续集成,持续集成包括我们 APP 可以做一些自动化测试,其实我们已经有一些核心流程的自动化测试和单元测试,后面我们可以看看做成平台性的测试。打包脚本的配置化,就是把 App 的打包脚本变成可配置的,存在数据库里面,随存随用。最后还可以尝试做功能性的 A/B Test,因为我们现在已经有灰度发布了,后面可能会做一些功能性的,比如说某些用户他使用的是 A 功能,另一部分用户使用的可能是 B 功能这样子。

  4. 最后关于多端融合方面,因为小菜端非常多,有 RN、小程序、H5、PC 等,我们可能会继续发挥 RN 快速迭代更新的优势,然后去探索一下和其他端型态的一些融合方案。

我今天的分享就到这里,下面是我的个人的二维码,一是钉钉的二维码,一个是微信的二维码,有兴趣的同学扫一扫加好友,后面进行线下交流。


本文使用 mdnice 排版