在 React Native 和 Flutter 之间进行选择
从我自己的博客文章交叉发布
Flutter 的兴起给新的移动项目决策带来了一些疑虑。这种疑虑在 2016/17 年人们需要跨平台移动解决方案时并不存在。当时的选择较少¹,很明显,如果你想要一个使用 JavaScript 的跨平台解决方案,你会选择 React Native,因为它的表现优于竞争对手。
我们不再质疑跨平台的可行性,而是在决定哪种解决方案才是最佳。尽管还有其他可能的解决方案,例如 Xamarin 等,但 React Native 和 Flutter 都是不错的选择。
在决定哪个选项最适合他们的项目需求之前,应该了解什么?
建筑学
首先要了解的是 React Native 和 Flutter 之间的核心区别。React Native 针对每个平台渲染原生 Widget,其 JSX 组件会转换为原生对应组件。这与之前使用 JavaScript 编写移动应用的尝试不同,因为尽管使用 JavaScript 声明 UI 元素,但 React Native 底层渲染的是平台原生 UI Widget。
另一方面,Flutter 并不渲染原生 Widget。它依赖于渲染引擎来绘制 2D UI 元素。Flutter 的引擎主要用 C++ 编写,并使用Google 的 Skia 图形库²提供底层渲染支持。这种架构决策为 Flutter 提供了底层渲染控制,从而可能提升其性能。
大多数 UI 元素在渲染引擎或平台自带的 Widget 渲染时,不会有太大差异。差异通常体现在与用户交互的元素上。原生 UI 元素通常在每个平台上都有独特的行为。例如,屏幕过渡在 iOS 上是滑入,而在 Android 上,滑动更像是淡入。此外,文本输入也具备平台内置的辅助功能。渲染引擎必须创建文本输入的所有基本功能,包括复制粘贴、光标定位,甚至文本显示。
React Native 核心团队表示,他们有意识地决定渲染原生小部件而不是渲染 UI 元素本身,但据他们所说,由于以下原因,这似乎从来都不是一个正确的方法;他们不想重新实现平台提供的所有内容;重新实现所有内容并跟上平台更新所需的工作量,包括对新旧多个操作系统外观的支持³。
Flutter 则致力于在所有平台上提供一致的 UI 观感。而 Reflectly 是一款最初用 React Native 编写的应用,在 Flutter 中重写了这一理念⁴。Flutter 让 Reflectly 开发团队能够在 iOS 上编写应用,并期望在 Android 上获得完全相同的观感。
由于 Flutter 比 React Native 需要更多资源,因此编写跨平台解决方案的工作量不容忽视。Flutter 正在尝试匹配原生 UI 小部件的行为,尽管他们已经发布了 1.0 版本,但这仍是一项持续进行的工作⁵。
开发者体验
开发者体验何时决定了项目使用的技术?希望如此。良好的开发者体验使开发团队能够编写出更好的软件,并让开发者感到满意。React Native 通过引入热重载和声明式 UI 框架⁶,对移动开发产生了巨大的影响。这两点提高了开发者的生产力和整体幸福感。
在使用 React Native 开发移动应用近三年后,第一次使用 Flutter 就给我留下了深刻的印象。它通过提供 Flutter Docter、热重载和详尽的文档,为用户带来了卓越的入门体验。可以肯定地说,任何有移动开发经验的人都能使用 Flutter 快速高效地完成开发。
React Native 开发者体验是一个持续改进的过程。直到去年,与如今相比,React Native 对开源社区以及开发者体验的关注度仍然较低。自去年年底以来,React Native 核心团队在改进与开源社区的互动方面做出了显著的努力。这些努力可以从“你不喜欢 React Native 的哪些方面?” 版本1和2中看出。Dan Abramov 目前负责改进热重载模块⁷,该模块存在一些 bug。
可用的 UI 元素
Flutter 和 React Native 都提供了你所需的所有 UI 元素,尽管如此,它们各自采取了不同的方法。Flutter 致力于为你可能需要的所有 UI 元素提供一流的支持,它拥有丰富的 Widget⁷,其目标本质上是让你不需要任何第三方集成,它鼓励你编写自己的 Widget。
另一方面,React Native 是一个渲染原生 UI Widget 的应用,因此它致力于打造一个精简的核心⁹。React Native 将托管你所需的最少模块集,而其他依赖项则交由第三方开源组件管理。使用 React Native,集成原生视图或模块不会产生任何开销,只需要通过桥接器进行通信,这也是架构重写(代号为 fabric¹⁰)的原因。
React Native 的 Lean Core 策略对某些人来说听起来不太好,因为从主仓库中移除一些 UI 元素意味着 Facebook 以外的其他人必须站出来做出贡献。Lean Core 最终带来了一个惊喜,所有提取出来的模块都得到了维护,并且比以往更新得更多。
需要注意的是,如果您的应用需要集成原生 UI 视图,Flutter 将负责所有渲染工作。因此,当您需要渲染原生 UI 视图(无论是 Android 还是 iOS)时,都必须将视图嵌入 Flutter 的层级结构中。对于 iOS,文档指出这是一项开销很大的操作¹¹。此外,由于嵌入视图并非易事,因此对于 Android,嵌入操作也并非十分流畅。
升级
重大变更是更新过程中的主要问题。React Native 的生命周期较长,但更新带来的困扰却屡见不鲜。这并非 React Native 独有,而是软件开发领域的普遍问题。尽管 Flutter 的诞生时间较短,但它也曾遇到过需要引入重大变更¹³的情况。Flutter 核心团队在一项调查中询问用户,为了更大的利益而做出的重大变更是否可以接受¹²。
有证据表明,两个社区都在尽力解决更新问题,并提供了清晰的文档和工具。Flutter 提供了一个 Github Wiki¹³ 来解决这个问题。而 React Native 的核心团队和社区也创建了一个工具¹⁴和文档来解决这个问题。
尽管核心团队付出了巨大的努力,但他们仍然无法免受针对性平台更新所引发的问题的影响。为了正确适配 AndroidX,他们付出了巨大的努力¹⁵。
社区
对于开源项目来说,健康的社区是一笔宝贵的财富。尽管 Flutter 才刚刚起步,但它已经获得了巨大的发展,并且仍在不断发展壮大。Flutter 2019 年首次用户调查的 Insights 数据就体现了它的蓬勃发展¹²。React Native 的社区非常强大,这得益于整个 JavaScript 生态系统的推动。两者都获得了来自外部开发团队的贡献,其中最引人注目的是 React Native 获得了来自微软、Callstack 和 Expo¹⁹ 等公司的大量贡献。Flutter 也获得了许多外部贡献,但我们无法明确这些贡献来自何处。在这一方面,Flutter 和 React Native 都展现了良好的发展势头。
表现
关于 React Native 与 Flutter 的对比,已经有数百篇文章,它们都声称 Flutter 的性能优于 React Native,然而,它们都缺乏基准测试。所有这些文章都基于
Flutter 架构背后的逻辑。理论上,Flutter 速度更快。Dart 代码(包括 SDK 中的代码和您的代码)都是提前 (AOT) 编译成原生 ARM 和 x86 库^20,因此原生代码调用速度更快。React Native JavaScript 线程必须每 5 毫秒通过批量异步调用跨接桥接。理论上,React Native 也在尝试使用 Fabric 解决桥接问题,这将使 JavaScript 能够通过 C++ 中保存的主机记录进行更快、更同步的通信。
如果我们编写了两个应用,一个用 React Native,另一个用 Flutter,并且只使用几个屏幕,你几乎感觉不到有什么区别。在网上只找到了一篇包含基准测试的文章¹⁶。这是一个计时器应用,通过查看基准测试,你会发现原生 Android 应用、Flutter 应用和 React Native 之间的差异非常小。然而,这篇文章有一个缺陷,它没有评估真正影响性能的关键点,即动画和大型列表。
动画是性能的关键。在速度较慢的设备上,用户会感觉到延迟。默认情况下,React Native 在这个测试中表现不佳,因为它自带的动画 API 是在 JavaScript 线程上编写和运行的。有很多帖子说动画 API 很慢¹⁷。为了解决这个问题,你可以使用 React Native Reanimated,它通过在原生线程¹⁸上运行所有内容来解决这个问题。
即使 React Native 的动画效果可能有所改进,你也不能否认 Flutter 使用 Skia 作为渲染引擎的事实。这是一个性能非常强大的框架,在 Flutter 的发布版本中,它展现出了在 Android 设备上渲染 120 FPS 的能力。
Flutter 在列表方面也表现出色,它提供了专门针对大型列表的开箱即用 API。ListView.builder 提供了开箱即用的虚拟化功能,性能非常出色。在 React Native 上,使用 FlatList 可以获得可接受的性能,但是,正如您在“优化 FlatList 配置”这篇文章中看到的那样,它需要进行一些调整。
React Native 在 Android 设备上的交互时间也一直备受质疑。尽管如此,Facebook 还是投入资源开发了 JavaScript 引擎,以提升其在 Android 设备上的性能。Hermes就是一个针对 React Native 进行优化的 JavaScript 引擎。
结论
还需要考虑其他一些因素,例如生态系统。JavaScript 是最流行和常用的语言之一。在 G2i 最近的一个项目中,我们决定使用 React Native 而不是 Native 开发,主要是因为我们想共享 JavaScript 中现有的所有服务和数据逻辑。
Flutter 和 React Native 都是跨平台开发的优秀工具。无论使用哪一种,都能交付高质量的应用程序。
关于我
你好!我是一名专注于 JavaScript 的软件开发者。我很乐意与你分享软件开发方面的知识,如果你想聊聊,可以随时联系我。
感谢您的阅读!
参考
[1] 大多数人只考虑过 React Native 或 PhoneGap/Cordova,它们彼此之间差异很大,尽管 Flutter 不是 JavaScript 解决方案,但它使用的 Dart 与 JavaScript 非常相似,其类似 C 的语法,并不稳定,不值得考虑。
[2] 维基百科贡献者。(2019 年 6 月 30 日)。Flutter(软件)。在维基百科,自由的百科全书。于 2019 年 7 月 7 日 14:04 检索自https://en.wikipedia.org/w/index.php?title=Flutter_(software)&oldid=904189137
[3] Reactiflux QA React 核心团队。(2019 年 1 月 24 日)。在 reactiflux.com 成绩单中,检索自https://www.reactiflux.com/transcripts/react-native-team/#youitv-engine-one-currently-binds
[4] Reflectly App 演示。 (2019 年 3 月 7 日)。在第 19 届世界移动通信大会上,摘自https://youtu.be/hdOxvNQbies?t=746
[5] 2019 年 7 月 7 日,我们在 Flutter 的代码库中发现了以下与 UI 元素行为相关的问题,如果使用原生 UI Widgets 则不会存在这些问题:https://github.com/flutter/flutter/issues/35068、https://github.com/flutter/flutter/issues/35577、https://github.com/flutter/flutter/issues/35694。还有很多,这只是一个例子。
[6] 我们可以从 React Native 之后出现的声明式移动框架/工具包的数量中看到这种影响的证据。 Flutter、SwiftUI、Jetpack Compose
[7] Widget 索引https://flutter.dev/docs/reference/widgets
[8] 与损坏的热重载模块相关的票证https://github.com/facebook/react-native/issues/18899
[9] 与 Lean Core 相关的票证https://github.com/facebook/react-native/issues/23313
[10] 这是对当前桥接架构的良好概述,https://hackernoon.com/understanding-react-native-bridge-concept-e9526066ddb8。与 Fabric 架构对应的问题https://github.com/react-native-community/discussions-and-proposals/issues/4。
[11] 嵌入 iOS 视图是一项昂贵的操作,如果可以实现 Flutter 等效操作,应避免执行此操作。https://api.flutter.dev/flutter/widgets/UiKitView-class.html
[12] Flutter 2019 年首次用户调查的见解。(2019 年 4 月 11 日)。在 Medium 文章中,检索自https://medium.com/flutter/insights-from-flutters-first-user-survey-of-2019-3659b02303a5
[13] Flutter 处理重大变更 Wiki https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[14] React Native 的升级助手https://github.com/react-native-community/upgrade-helper
[15] Flutter 和 React Native 对 AndroidX 支持努力的证据。https://flutter.dev/docs/development/packages-and-plugins/androidx-compatibility
https://github.com/react-native-community/discussions-and-proposals/issues/129
[16] Alex Sulivan - 检查 Native、Flutter 和 React Native 移动开发之间的性能差异。 Thoughtbot 开发网站: https: //thoughtbot.com/blog/examining-performance-differences-between-native-flutter-and-react-native-mobile-development
[17] 各种抱怨动画性能的帖子:https://www.reddit.com/r/reactnative/comments/6ex9y1/brutally_slow_animations_on_android/,https : //stackoverflow.com/questions/48928229/slow-animations-in-reactnatives-android-app
[18] react-native-reanimated https://github.com/kmagiera/react-native-reanimated
[19] 来自 Amazon、Callstack 和 Expo 的 React Native 存储库拉取请求
[20] https://flutter.dev/docs/resources/faq#how-does-flutter-run-my-code-on-android