WalmartLabs 使用 React Native 的体验

  • 刘志勇

2017 年 2 月 3 日

话题:语言 & 开发架构

React Native是 Facebook 于2015 年开源的跨平台移动应用开发框架,是 Facebook 早先开源的 UI 框架React在原生移动应用平台的衍生产物,目前支持 iOS 和 Android 两大平台。React Native 使用 Javascript 语言,类似于 HTML 的 JSX,以及 CSS 来开发移动应用,因此熟悉 Web 前端开发的技术人员只需很少的学习就可以进入移动应用开发领域。

React Native 运行时包含一个原生主线程和一个 JS 线程,JS 线程执行 JS 代码,负责界面布局和业务逻辑处理,原生线程负责界面渲染和原生功能执行。React Native 尽量使用原生组件(现有原生组件经过封装后可在 JS 里调用),以避免重复造轮子。这样有很多好处,一是可以利用现有的大量的原生组件;二是可以达到跟原生组件一样的性能;三是通过 JS 封装过后的组件可以支持跨平台。

不久前,WalmartLabs 的 React Native 团队成员Matt BresnanM.K.SafiSanket PatelKeerti合著了一篇文章,为我们分享了 WalmartLabs 使用 React Native 的体验。

InfoQ翻译并分享给大家,以下是正文:


Walmart的文化中,客户总是第一。因此我们一直努力改善为顾客提供的购物体验。目前沃尔玛的 App 有许多嵌入式 Web 视图,我们发现这些实现没有达到我们对 App 的要求的标准。混合 Web 视图的实现性能欠佳,即时在高端设备上,也没有在原生运行的感觉。不仅如此,由于 Web 视图严重依赖网络请求(我们使用服务器端渲染 Web 实现),网速较慢的顾客可能体验非常槽糕。所以,我们就想知道:“我们能否修改或者替换当前的实现,为顾客提供更好、更流畅的体验吗?”于是,我们开始了寻找答案的漫漫长路。

可能的解决方案

集思广益之后,我们想出了以下解决方案:

  1. 纯原生实现(没有更多的 Web 视图)
  2. React Native

理论上,原生实现表现卓越。但实际上我们要考虑到生产力、代码共享、上市时间,因为这是一个像 React Native 那样的跨平台框架。除了 React Nativewait,还有其他跨平台的移动开发框架,如 PhoneGap、Xamarin 和 Meteor 等。但由于我们目前的 Web 代码库使用了 React 和 Redux,相对于其他跨平台框架,考虑 React Native 是最有意义的。更不必说,它是一个相当稳定的跨平台框架,可能会持续流行一阵。

下面是我们使用 React Native 得到的好处:

生产率

  • 95%的代码库在 iOS 和 Android 之间共享
  • 无需知识共享,因为每个功能都由单个团队实施
  • 极佳的开发体验。无需重新打包即可看到简单的更改
  • React Native 是用 JavaScript 编写的。我们可以利用整个团队的编程技能 / 资源

代码共享

  • 前端 / 演示代码可以在 iOS 和 Android 之间共享
  • 业务逻辑(redux 存储)也可以与 Web 应用程序共享
  • 平台之间的许多代码可重用性

应用商店批准

  • 无需通过应用商店审批流程。我们可以在自己的服务器上托管软件包,并进行无线升级

上市时间

  • 非常快
  • 我们可以控制发布日期
  • 这两个平台可以在同时发布

性能

  • React Native 提供与原生几乎相同的性能

动画

  • React Native 提供了非常流畅的动画,因为代码在渲染之前转换为原生视图

UX

  • 我们可以有平台特有的 UI 设计

自动化

  • 相同的自动化套件可以在 iOS 和 Android 上运行

性能

当我们在WalmartLabs进行性能测试时,我们有几个目标。我们想知道在 RAM 使用、FPS、CPU 利用率等方面,React Native 和其他竞争对手相比,表现怎么样。我们还想知道 React Native 的扩展能力怎么样:因为 React Native 有望成为我们整个企业的移动开发技术标准。由于该项目是 WalmartLabs 的实验,我们的短期目标是证明该技术与当前的方案性能相当或者更好。我们长久以来所追求的是,集成我们的 CI 进行性能测试,正如Facebook所做的那样,我们可以测试每个更改对整体应用效果的影响。

性能测试的麻烦

截至目前,React Native 的性能测试是一件痛苦的事。对于 BAT 来说,由于两个不同的平台,因此有两套用于收集数据的工具。Apple 提供了测试工具软件,为我们提供了此后的大多数测量。Android 需要使用多个实用程序来收集所有想要的数据。此外,有许多测量,没有简单的办法来获得数据流,所以一些测量必须靠估计。

Facebook 试图通过在 React Native 开发人员菜单中提供一个性能监视器来弥补 Android 和 iOS 性能测试之间的差距。不幸的是,这个解决方案远非完美。在 iOS 上,它提供 RAM 使用、FPS 数据以及一系列与 React Native 相关的测量,但是对于 Android,perf 监视器仅提供 FPS 数据。在未来,如果可能的话,我希望能看到两个平台提供测量的标准化。

关闭并告诉我 React Native 是怎么做的!

好的,但请注意,我们报告提及的性能数据等是基于我们的 App,可能不代表您的应用程序也一样。然而,我会尝试提供可从我们的测试中得出的一般结论。

我们收集的数据是有希望的。它已经表明,React Native 确实是一个可行的解决方案,无论移动应用程序是大还是小,它都适用。在图形性能、RAM 使用和 CPU 等方面,我们采取的每一项措施都与当前的混合解决方案相当或者更好,对两个平台都是如此。App 的整体感觉有显著改善,用户体验远超过了混合解决方案。

React Native 很快——真的很快。虽然我们没有一个纯粹的原生版本来测试,但是,就外观和感觉来讲,

编写纯原生应用并不会比 React Native 好多少。总的来说,我们对 React Native 的性能感到非常满意,希望我们收集的结果能够得到业务部门的批准,最终我们的用户受益于此。

测试

为了确保我们的 React Native 代码质量,我们的目标是 100% 涵盖单元测试和集成测试的测试范围。

集成测试

iOS 和 Android 平台上的的 Walmart App 由数百名工程师合作构建。随着代码库的不断发展,我们使用集成测试,以确保我们的 React Native 代码正常运行。

在沃尔玛,我们需要支持各种设备和操作系统。Sauce 实验室允许我们在 iOS 和 Android 硬件和操作系统版本的几种组合上进行集成测试。在多个设备上运行集成测试需要很长时间,所以我们每天晚上只做一次。

我们还使用集成测试来预防回归。我们使用 GitHub Enterprise 连接TeamCity CI,以便对每个 pull 请求进行测试。与夜间作业不同,在 pull 请求时,只在一个设备上运行测试。但即便如此,可能会需要更长的时间,因此,我们采用一些工具来缩减这个时间。Magellan是我们的开源项目之一,它允许我们并行运行测试,显著减少测试时间。

测试本身用 JavaScript 编写,由 Mocha 运行,并使用Appium命令来控制移动模拟器。React Native 允许我们在每个组件上设置一个testID属性。这些testID作为 CSS 类名称。我们使用它们来准确、方便地指定使用 XPath 的组件,并与测试的目的进行交互。

单元测试

我们使用单元测试来独立地运行 React Native 组件,并防止无意的更改。

我们使用常见的 React 单元测试工具,如 Mocha、Chai、Sinon 和 Enzyme。但是 React Native 有一些独特的挑战,因为它的组件具有阻止它在 Node 上运行的环境依赖性react-native-mock为我们解决了这个问题,因为它提供了模拟的 React Native 组件,当在 iOS 或 Android 之外运行时不会中断。当我们发现自己需要模拟额外的依赖时,我们使用重新连接Node 模块。

可重用性

我们利用相同的自动化测试套件在 iOS 和 Android 上运行。

部署

React Native 的一个主要优点是能够通过无线方式快速修复 bug,绕过应用商店,这意味着 React Native JavaScript 包将托管在服务器上,并由客户端直接检索,类似于 Web 的工作原理。

然而,React Native 提出的一个挑战是,为了使 JS 捆绑包工作,在本地端必须有一个兼容的 React Native 对应端。如果将本机端升级到最新的 React Native,并且用户更新了应用程序,但是他们下载了旧的捆绑包,则应用程序将中断。如果您更新该捆绑包以匹配最新的本机端,并将其提供给尚未更新其应用程序的用户,则它也会中断。

像 Microsoft CodePush等工具可用于将软件包映射到正确的应用程序版本。但是同时支持多个版本的应用程序是一个开销,在决定使用 React Native 时应该考虑。

挑战

iOS 和 Android 之间的区别

React Native 的功能在 iOS 和 Android 上有太多的不一致,使得支持这两个平台变得棘手起来。React Native 在不同平台的一些行为和风格实也不同。例如,iOS 上支持 style 属性溢出,但 Android 不支持。组件属性也可以是平台特定的。在 React Native 文档中,您可以看到标记为“仅限 Android”或“仅限 iOS”的许多属性和功能。测试自动化代码还需要针对每个平台进行调整。

我们发现 iOS 比 Android 有更多的功能,所以对于一款针对这两个平台的产品,用 Android-first 方法开发是有意义的。

开发和调试

我们的经验中的一个痛点是 React Native 代码在调试模式与正常模式下的行为不同,因为 React Native对这两种模式分别使用不同的 JavaScript 引擎。当一个 bug 是正常模式特有时,自然很难调试,因为它在调试模式下是不可重现的。

结论

React Native 有一些卓越的特点。React Native 的定义特征(可以说是其最好的卖点)是它的跨平台:允许同一个团队在 iOS 和 Android 上同时开发,这可以将人工成本降低一半。初始开发以及增量功能的开发非常快,因此您可以比竞争对手更快地满足客户的需求。就像蛋糕上的糖衣,一般来说以 React Native 编写的应用程序与原生应用程序相比,有相当的、甚至更好的优异性能。

虽然 React Native 有一些奇妙的卖点,但在开始使用 React Native 的项目之前,还需要记住一些事情。首先,虽然 React Native 在弥补 iOS 和 Android 之间的差距方面做得很好,你不会在两个操作系统之间实现完全的奇偶校验。有一些平台可以做,其他人不能处理,主要涉及到样式视图,但也有更重要的注意事项,如性能测试。虽然开源社区对开发和发布新功能和性能调整非常满意,但实际上,升级你的 React Native 版本往往是一个巨大的痛苦,特别是如果你有一个围绕 React Native 建立的平台,就像我们在 Walmart 的那样。

我们坚信 React Native 是一个奇妙的框架。它做到了我们想要的一切,令人钦佩。从创业公司到财富 500 强公司,如果你想采用一个新的移动项目,考虑使用 React Native 那,不会让你后悔的!


感谢郭蕾对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。

语言 & 开发架构