在开始寻找最佳的跨平台移动开发框架的过程中,Flutter、React Native 和 Ionic 是让我印象深刻的。这三款产品很有吸引力,因为它们承诺在为多个平台使用单一代码库的同时提供良好的性能。
为了开始冒险进入这个新世界,我创建了三个版本的移动应用程序,这些应用程序使用 API 并在屏幕上显示基本数据。这个想法很简单:构建一个应用程序,显示一个随机国家的详细信息。我以前在 Python 中做过类似的项目。
为了公平地比较,该应用程序的所有三个版本都必须满足以下要求:
- 屏幕加载后,将显示一个国家/地区
- 在第一个国家/地区出现之前显示加载中
- 一个圆形按钮,用于获取另一个随机国家/地区
- 整个国家/地区列表仅获取一次(来自 RESTCountries)
让我们先深入了解一下我使用 Flutter 构建移动应用程序的经验。
Flutter
正如 Flutter 网站上所描述的那样,“Flutter 是 Google 的一个开源框架,用于从单个代码库构建漂亮的、原生编译的多平台应用程序。它创建于 2017 年,基于面向对象的编程语言 Dart。
在开始开发之前,我花了一个小时阅读 Flutter 的文档和观看教程。Flutter 背后的团队充满热情和吸引力,这激发了我深入研究的动力。
开发环境和 Android 模拟器的设置进行得很顺利。这是意料之中的,因为我使用 Google IDE (Android Studio) 来使用 Google 框架 (Flutter) 为 Google 操作系统 (Android) 创建应用程序。
是时候创建应用程序了。计时器打开。在 4 小时内,我制作了这个:
在开发过程中没有遇到任何特别复杂的问题。在开发过程中,Android Studio 的建议帮了大忙。还有热重载?真是省时省力!只需按下 Ctrl+S 键,您就能看到您的更改立即反映在设备上,而无需刷新页面!
尽管在设置和工具方面有很好的体验,但当我深入开发时,我还是遇到了一个突出的设计模式:小部件的普遍使用。Flutter 的“一切皆小部件”概念变得显而易见,这导致了大量的嵌套和元素样式的混合。甚至连填充都是小部件!与我习惯的基于组件的结构相比,这种方法感觉不太直观。
看看这个例子就明白我的意思了:
class CountryDetails extends StatelessWidget {
final Country country;
const CountryDetails(this.country, {super.key});
@override
Widget build(BuildContext context) {
var formatter = NumberFormat.decimalPattern('en-US');
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Image.network(country.flag, height: 200),
),
CountryProperty('Name: ', country.name),
CountryProperty('Region: ', country.region),
if (country.capitals.isNotEmpty)
CountryProperty('Capital: ', country.capitals[0]),
CountryProperty('Population: ', formatter.format(country.population)),
],
);
}
}
在屏幕实际内容的正上方创建填充,这是一个小的 UI 细节,这让我有轻微的不适感。我只能想象它在具有众多 UI 要求的场景中会是什么样子。当这些不同的关注点在同一视野内争夺注意力时,保持专注将具有挑战性。
React Native
React Native 由 Meta 于 2015 年创建,是一个开源 JavaScript 框架,可让您构建原生 Android 和 iOS 应用程序。React Native 已在业界获得广泛采用,是 Facebook 和 Instagram 等知名应用程序的基础。
我以前使用过 React 库。VS Code 已经安装好了。我只需要运行 React Native。
哦,那可真是太痛苦了。当我开始使用 React Native 时,与 Flutter 的流畅设置相比,这是一场完全不同的游戏。一开始,我就面临着两种管理工作效率的选择:Expo Go 和 React Native CLI。我没有意识到这两个选项是相互排斥的,因此在不了解它们之间区别的情况下,我试图按照网上的解决方案进行操作。这导致依赖关系一团糟,难以管理。如果您想为 React Native 设置环境,请确保只遵循官方文档。这样做,你可能会避免遇到同样的挫折。
尽管图像显示方面的问题尚未解决,应用程序还是在 2.5 小时内完成了。为了确保旗帜显示出来,我强制调整了宽度和高度,但有时会导致旗帜变形。我根本无法在安卓设备或模拟器上显示旗帜。它只能在浏览器中运行。
React Native 在代码方面提供了一种简洁易读的方法。这种简洁性来自于 React 基于组件的架构,它促进了模块化和代码可重用性。每个组件都是一个 JavaScript 函数。通过使用 JSX(JavaScript XML),React 允许我们编写类似 HTML 的代码来描述组件的 UI。在我的示例中,它看起来像这样:
const CountryDetails = (props) => {
return (
<View>
<Image source={{ uri: props.flag }} style={{ marginBottom: 10, width: 300, height: 200 }} />
<CountryProperty property="Name" value={props.name} />
<CountryProperty property="Region" value={props.region} />
{props.capital && <CountryProperty property="Capital" value={props.capital} />}
<CountryProperty property="Population" value={props.population.toLocaleString("en-US")} />
</View>
)
}
Ionic
Ionic 成立于 2012 年,是“一个开源的移动 UI 工具包,用于从 React、Vue 或 Angular 中的单个代码库构建现代、高质量的跨平台移动应用程序。Ionic 将大量投资投入到一组丰富的 UI 组件和有吸引力的用户界面上,以适应目标平台。
Ionic Angular 是我选择的应用程序。Angular 是 Google 于 2016 年构建的成熟框架,用于他们的许多 Web 应用程序。我花了 30 分钟观看 Ionic 视频和阅读指南。熟悉的 Angular 开发生态系统让我有信心在短暂的学习期后启动应用程序。
我按照网站上的说明,从空白模板启动应用程序。设置完成后,结果是一个生成了多个 JSON 和 TypeScript 配置文件的项目,这让我很不舒服。“为什么我需要这么多文件”?我想。但至少有了一个中间有文本的应用程序,可以在浏览器中快速预览。
开发过程非常简单,仅用了 2 个小时即可实现与 Flutter 和 React Native 版本相同的功能。但是如果我说我没有从 React Native 版本(即 Country 类的构造函数)复制一些代码,那我就是在撒谎。
Ionic 提供了一组 UI 组件,使 UI 实现变得更加容易。我使用了 Spinner 和Floating Action Button。该文档提供了简单的示例,以便无缝集成。
与 React 相反,Angular 不使用 JSX。相反,它使用模板语法。模板是 HTML 的一部分,但添加了更多功能,例如插值、事件绑定和指令。
<ion-content [fullscreen]="true">
<div id="container">
<div *ngIf="currentCountry; else loading">
<img [src]="currentCountry.flag" style="margin-bottom: 10px; width: 300px;"/>
<app-country-property property="Name" [value]="currentCountry.name"></app-country-property>
<app-country-property property="Region" [value]="currentCountry.region"></app-country-property>
<app-country-property *ngIf="currentCountry.capital" property="Capital" [value]="currentCountry.capital"></app-country-property>
<app-country-property property="Population" [value]="currentCountry.population.toLocaleString('en-US')"></app-country-property>
</div>
<ng-template #loading>
<ion-spinner></ion-spinner>
</ng-template>
</div>
</ion-content>
通过将 UI 分离为特定的 .html
文件,我的 TypeScript 文件变得只关注逻辑,这可能会减轻在同一屏幕上工作的开发人员之间的协作冲突。
Flutter、React Native 和 Ionic 之间的比较
代码风格和语言
在我看来,基于 JavaScript 的框架在代码可读性和简单性方面胜出。与 Flutter 相比,我用更少的代码行实现了相同的功能。我不太喜欢 Flutter 的嵌套代码风格。它看起来令人困惑且难以阅读,边距、填充、大小、元素和逻辑都混淆了,这与 React Native 和 Ionic 相反。您是喜欢 JSX 还是 Angular 模板来实现视图,最终取决于个人喜好。我倾向于 Angular,因为它的文件结构与将在 DOM 中呈现的内容非常相似。
虽然我以前知道一些 React 和 Angular(但既不是 React Native 也不是 Ionic),这可能影响了开发时间差,但我确实觉得它们比 Flutter 更容易学习。
生态系统
评估框架采用情况的一种有趣方法是检查使用它们构建的已安装应用程序的数量。截至 2024 年 4 月,在美国,前 500 名安装应用程序(来自 Play 商店)中有 12.57% 是使用 React Native 构建的,相比之下,Flutter 占 5.24% 的份额,Ionic 仅占 0.52%。
这三个框架提供了大量的文档。他们也都在交互式示例上进行了一定程度的投资,但我觉得 React Native 在设置和工具方面有时更令人困惑。我亲眼目睹了我对 Expo Cli 和 React Native Cli 的迷失方向。这并不完全是 React Native 的错:有许多非官方的指南,有许多不同的方法来启动应用程序。 React Native 在构建项目时也提供了很大的自由度,尽管它带来了很多解决方案,但在某些领域提出了缺失的文档和不明确的最佳实践。
Flutter 的采用率正在增长,超过了 React Native 和 Ionic 的公共 GitHub 存储库的数量。尽管如此,当我们比较语言而不是框架时,比 Dart 大 16 岁的 JavaScript 仍然是采用率的明显赢家。JavaScript 是为前端开发而生的,但现在也被广泛用于服务器端。整个 JavaScript 生态系统充满了所有类型的资源,包括用于众多用例的第三方库。如果你学习 Flutter,你只是在学习 Flutter。如果你使用 React Native 或 Ionic 进行构建,您将学习如何使用标准技术构建 Web 组件。
工具
热重载
为了在浏览器中进行测试,所有三个框架都将在进行更改时重新加载应用程序。在我的手动测试中,他们三个在代码更改后执行了非常快的重新加载,在 1-2 秒后显示另一个随机国家/地区,其中包括对国家 API 的 1 次调用。
在 Android 设备或模拟器中进行测试时,Flutter 凭借 Hot Reload 取得了胜利。更改文件足以更新视图,而无需刷新整个页面。它只是重建小部件树。然而,在 React Native 和 Ionic 中,文件中的任何更改都会触发整个页面的刷新(包括额外的 API 调用),这使得比较 UI 更改之前和之后的难度略有增加。尽管在某些情况下,React Native 应该能够通过快速刷新来保留状态,但在我的测试中,它没有,显示出与 Ionic 的 Live Reload 相同的结果。
远程调试
这些框架使用不同的调试方法;总而言之,我们可以通过浏览器远程调试 Android 应用程序。在我的测试中,Flutter 是打开应用程序(已安装)进行无线调试的最快方法。
- Flutter: 10 秒
- React: 17 秒
- Ionic: 21 秒
Flutter DevTools 具有简单直观的界面,其中包含许多可以在著名的 Chrome 开发者工具中找到的功能。我发现有趣的是,有一个选项可以放慢动画速度来帮助微调它们。它还包括应用内 UI 调试功能,这将有助于更好地了解实现的设计规范,例如边距和大小。
说到Chrome开发者工具,调试Ionic应用程序类似于调试标准网站,这是一个很大的优点。熟悉此界面简化了调试过程。从性能到网络,以及快速尝试 CSS 更改的可能性,Chrome 开发者工具都能满足我们的需求。Ionic 是这三个框架中唯一不提供任何应用内调试功能的框架。
尽管 React Native 具有应用内调试功能,例如性能叠加、网络信息和元素检查器,但在远程调试方面,它仍然落后于 Flutter 和 Ionic。React Native 提供 React DevTools,它专注于应用程序的组件层次结构。也可以使用 Hermes 引擎,该引擎将允许(仅)使用 Chrome 开发者工具的一些功能进行调试。
应用大小
虽然我还没有探索任何减少发布.apk大小的方法,但 Ionic 产生了 3.2MB 的文件大小,而 Flutter 产生了 18.1MB 和 React Native 25.2MB。安装后,它们分别占用了 9.61MB、34.66MB 和 55.47MB。
用户体验
构建具有一致和现代外观的跨平台移动应用程序对于提供无缝的用户体验至关重要。Flutter 的预构建 UI 组件和 Ionic 的自适应样式功能都确保了 Android 上的 Material Design 和 iOS 上的 Cupertino 的一致性。换句话说,Flutter 和 Ionic 使 UI 组件的外观适应目标平台。
使用 React Native,必须依赖第三方库才能开发出符合 Material Design 的用户界面。对于许多开发人员来说,维护额外的依赖关系很容易成为禁忌。当我不得不在 React Native 版本的浮动操作按钮中实现更多样式时,我感受到了其中的差异,最终获得了与 Flutter 和 Ionic 相似的用户界面。
性能
从理论上讲,当它编译为原生代码时,Flutter 应该比 React Native 运行得更快,因为后者依赖于 JavaScript 桥接。这是一种用于允许 JavaScript 代码访问移动设备的本机功能的技术。这样的过程可能会给应用程序的性能带来开销。Ionic 是三者中速度较慢的,因为它运行在 Web 视图(用户不可见的浏览器)上。然而,Ionic 指出,它比 React Native 慢的神话只是......一个神话。
鉴于其几乎不存在的性能要求,我无法用我的应用程序测试这种比较。
结论
我有兴趣更深入地研究 Flutter 的代码风格,尽管我还没有完全接受它。关于最佳实践,有很多东西需要学习,而热重载功能似乎是调试的游戏规则改变者。尽管如此,将现有的 TypeScript、HTML 和 CSS 知识转移到移动应用程序的开发中也非常有吸引力。对 JavaScript 生态系统的熟悉和建立的信心使我倾向于暂时将 Flutter 放在一边。
从开发到调试,包括与现有 Web 库的集成,构建 Ionic 应用程序感觉就像构建传统的 Web 应用程序一样。这让我相信,提高我在 Ionic 开发方面的技能不仅会提高我作为移动开发人员的熟练程度,还会提高我作为 Web 开发人员的熟练程度。与 React Native 相比,Ionic 在实现遵循 Android 和 iOS 设计原则的接口方面也取得了胜利。
重要的是要承认,虽然获得了有价值的见解,但许多方面,如代码组织、关注点分离和组件可重用性,可能只会随着项目的发展而变得明显。
正如移动开发行业所显示的那样,无论使用哪种框架,都可以开发出性能良好并能使用本地功能的优秀应用程序。因此,不要低估选择一个自己喜欢的框架的重要性。与其花几个小时在网上寻找答案,为什么不使用示例应用程序进行探索呢?
希望你能从我的故事和我作为跨平台移动开发学徒的角度,度过一段愉快的时光。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。