Flutter 是一款移动 SDK,其核心在于赋能每个人构建美丽的移动应用。 无论您来自 Web 开发领域还是原生移动开发领域,Flutter 都能让您以一种熟悉、简化的方式更轻松地创建移动应用,而无需将控制权交给框架。
截至本文撰写之时,Google AdWords 和阿里巴巴都在生产环境中使用 Flutter。 您可以在 Flutter 网站的展示页面上查看更多使用 Flutter 的示例(包括我参与开发的应用)。
目前,Flutter 非常火热。 我最常看到的疑问是:“Flutter 还是 React Native……我应该用哪个?” 就像编程中的所有事情一样,这都取决于您愿意做出的权衡。
我将尝试说服您,Flutter 是移动应用开发的最佳选择。 我相信它优于任何其他跨平台框架,并且可能优于原生开发——但稍后会详细介绍。
但在此之前,让我快速浏览一下 Flutter 是什么以及它不是什么,从 Dart 编程语言开始。
什么是 Dart?
Dart 是一种由 Google 创建的编程语言,用于编写 Flutter。 Dart 的诞生,或多或少是因为 Google 想要一种比 JavaScript “更好”的语言来编写服务器端和前端代码。 就我了解,他们对 JavaScript 的主要问题在于,由于它依赖于庞大的委员会审批和多个浏览器厂商的实施,因此新功能的更新速度很慢。
经过一系列关于是否直接采用 JavaScript 的决策后,Google 决定开发一种在语义上与 JavaScript 兼容的语言。 换句话说,您在 Dart 中编写的每一件事都可以编译成 JavaScript。 这就是他们没有直接使用 Java 的原因——在语义上,Java 的规模太大了。
这是 2010 年 Google 的一封泄露的邮件链。 这是他们意识到需要对 JavaScript 做些什么的“顿悟”时刻。
Dart 的基本原理与所有高级语言类似。 也就是说,编程语言实际上很难学习。
不过,好消息是,Dart 非常适合作为一种“安全”的学习语言。 Google 并没有着手用 Dart 创建任何创新的东西。 他们希望开发一种简单、高效的语言,并且可以编译成 JavaScript。
它的语法没有什么特别令人兴奋的地方,也没有会让您困惑的特殊运算符。 在 Dart 中(与 JavaScript 不同),只有一种方法表示真:True。 只有一种方法表示假:False。
在 JavaScript 中,这会强制转换为 True
if (3) { ... }
在 Dart 中,这会使您的程序崩溃。 Dart 本质上是一种高效、可预测且简单的语言。
这一点很重要,因为用 Flutter 编写应用只是在编写 Dart 代码。 Flutter 的底层实际上是一个 Dart 类库。 不涉及任何标记语言或 JSX 风格的混合语言。 每个前端代码片段都用 Dart 编写。 没有 HTML。 没有 CSS。
为什么 Flutter 使用 Dart?
如果您来自其他任何背景(并且像我一样),您可能抱怨过 Flutter 使用 Dart 而不是 JavaScript。(开发人员,信不信由你,都是有主见的。)
并且有理由对这种选择表示怀疑。 它不是当今的热门语言之一。 它甚至不是 25 种最常用语言之一。 为什么?Google 是否仅仅因为它自己的语言而使用它? 我想这可能起到了作用,但也有实际的原因。
- Dart 支持即时 (JIT) 编译和提前 (AOT) 编译。
- AOT 编译器将 Dart 转换为高效的原生代码。 这使得 Flutter 速度很快(对用户和开发人员来说都是胜利),但也意味着几乎所有框架都是用 Dart 编写的。 对于您,开发人员来说,这意味着您可以自定义所有内容。
- Dart 的可选 JIT 编译允许热重载存在。 快速开发和迭代是使用 Flutter 的乐趣的关键。 当您在文本编辑器中保存代码时,您的应用将在不到一秒的时间内更新到您的模拟器中。
- Dart 是一种高效且可预测的语言。 它易于学习,并且感觉很熟悉。 无论您来自动态语言还是静态语言,您都可以轻松上手。
- 是的,我猜想使用同一公司开发的语言极具吸引力,因为 Flutter 团队可以与 Dart 团队紧密合作以实现所需的新功能。
Dart 是面向对象的。 这使得仅使用 Dart 轻松编写视觉用户体验成为可能,而无需标记语言。
Flutter 与 React Native(以及其他选项)的比较
在提供我对其他选项的未经请求的意见之前,我想明确一点:Flutter 并非在所有情况下都是答案。 它是一种工具,我们应该为手头的任务选择合适的工具。 也就是说,我只是认为您应该在未来认真考虑它。
原生开发(iOS 和 Android)
您的首选是为 iOS 和 Android 编写原生应用。 这让您可以最大程度地控制、调试工具,以及(可能)获得非常高性能的应用。 在公司中,这可能意味着您必须编写两遍代码;每个平台编写一次。 您可能需要不同团队的不同开发者,他们拥有不同的技能,并且无法轻松地互相帮助。
React Native、WebView 和其他跨平台 JavaScript 选项
您的第二个选择:跨平台、基于 JavaScript 的工具,例如 WebView 和 React Native。 这些并不是糟糕的选择。 您在原生开发中遇到的问题消失了。 团队中的每个前端 Web 开发人员都可以参与进来并提供帮助——他们只需要一些现代 JavaScript 技能。 这正是 Airbnb、Facebook 和 Twitter 等大型公司在其核心产品中使用 React Native 的原因。(Airbnb 最近 宣布 将停止使用 React Native,原因是我将在下面描述的一些问题。)
最初构建的跨平台“移动应用”只是在 WebKit(一种浏览器渲染引擎)上运行的 WebView。 这些实际上只是嵌入的网页。 问题在于,操作 DOM 非常昂贵,并且性能不足以提供出色的移动体验。
一些平台通过构建“JavaScript 桥”解决了这个问题。 此桥梁允许 JavaScript 直接与原生部件进行通信。
这比 WebView 性能更高,因为您消除了 DOM,但它仍然不是理想的。 每次您的应用需要直接与渲染引擎通信时,它都必须编译成原生代码才能“跨越桥梁”。 在单个交互中,桥梁必须被跨越 *两次*:一次从平台到应用,然后从应用返回到平台。

Flutter 不同,因为它使用自己的渲染引擎 Skia,这是 Chrome 中使用的相同渲染引擎。 Skia 可以与 Flutter 应用通信。 因此,Flutter *直接* 接收本地事件,而不是必须先将它们编译成 JavaScript。 这之所以成为可能,是因为 *Flutter 编译成原生 ARM 代码*。 这是它成功的秘诀。 当您的应用在用户的设备上启动时,它完全在设备操作系统期望的语言中运行。

JavaScript 桥梁无疑是现代编程的奇迹,但它也存在三个主要问题。
第一个问题是调试很困难。 当运行时编译器中出现错误时,必须通过 JavaScript 桥梁回溯错误,并在 JavaScript 代码中找到它。 它也可能在标记或类似 CSS 的语法中。 调试器本身可能无法像我们希望的那样工作。
然而,第二个更大的问题是性能。 JavaScript 桥梁非常昂贵。 每次应用中的某个内容被点击时,该事件都必须通过桥梁发送到您的 JavaScript 应用。 结果,通俗点说就是 *卡顿*。
第三个大问题,根据Airbnb的说法,是他们发现自己不得不比他们想要的更频繁地深入到原生代码中,这对他们主要由JavaScript开发人员组成的团队来说是一个问题。(Flutter在这个问题上还没有定论,但我可以肯定的是,在我的工作中从未需要尝试编写原生代码。我的团队中的一些成员创建了Objective-C和Java的插件。)
Flutter的直接优势
你很可能因为正在阅读这篇文章而对Flutter感兴趣……但你可能也持怀疑态度。我钦佩你对技术进行审查的细致程度。
你持怀疑态度的理由是合理的。这是一项新技术。这意味着API可能会发生重大变更。这意味着缺少对重要功能的支持(例如谷歌地图)。谷歌有一天可能会完全放弃它。
而且,尽管你认为Dart是一门很棒的语言,但这并不能改变Dart没有被广泛使用的事实,并且你可能需要的许多第三方库可能不存在。
不过,我将反驳所有这些观点。API不太可能发生变化,因为谷歌在内部使用Flutter开发主要的创收应用,包括Google AdWords。Dart最近更新到了版本2,这意味着它可能需要一段时间才会发生重大变化。可能需要几年时间才会引入重大变更,在计算机世界里,这几乎是永远。
是的,确实缺少一些功能,但是Flutter让你可以完全控制添加自己的原生插件。事实上,许多最重要的操作系统插件已经存在,例如地图插件、相机、定位服务和设备存储。Dart和Flutter的生态系统和社区已经存在。当然,它比JavaScript社区要小得多,但我认为它很简洁。我每天都看到人们在为现有的软件包做出贡献,而不是创建新的软件包。
现在,让我们谈谈Flutter的具体优势。
没有JavaScript桥
这是开发和应用程序性能的主要瓶颈。同样,它会导致卡顿。滚动不流畅,并不总是高效的,并且难以调试。
Flutter编译成真正的原生代码,并使用Skia进行渲染。应用程序本身在原生环境中运行,因此无需将Dart转换为原生代码。这意味着它在用户设备上运行时不会损失任何性能或生产力。
编译时间
如果你来自原生开发,那么你主要的痛点之一就是开发周期。iOS以其疯狂的编译时间而闻名。在Flutter中,完整的编译通常需要不到30秒,增量编译则只需几秒钟,这要归功于热重载。在我的日常工作中,我们首先为我们的移动客户端开发功能,因为Flutter的开发周期让我们能够快速移动。只有在我们确定了实现方案后,我们才会去编写Web客户端的功能。
一次编写,一次测试,随处部署
你不仅可以编写一次应用程序并部署到iOS和Android,而且只需要编写一次测试。Dart单元测试非常简单,Flutter包含一个用于测试Widget的库。
代码共享
在这里我将公平地说:我想这在技术上在JavaScript中也是可能的。但是,在原生开发中肯定是不可能的。使用Flutter和Dart,你的Web和移动应用程序可以共享所有代码,除了每个客户端的视图。(当然,只有在你使用Dart开发Web应用程序时才有可能。)你可以很容易地使用依赖注入来运行AngularDart应用程序和Flutter应用程序,使用相同的模型和控制器。
当然,即使你不想在Web应用程序和移动应用程序之间共享代码,你也可以在iOS和Android应用程序之间共享所有代码。
从实际角度来看,这意味着你的生产力非常高。我提到过,在我们的日常工作中,我们首先开发移动功能。因为我们在Web和移动之间共享业务逻辑,所以一旦移动功能实现,我们只需要编写期望相同控制器数据的视图。
生产力和协作
iOS和Android的独立团队的日子一去不复返了。事实上,无论你在Web应用程序中使用Dart还是JavaScript,Flutter开发都足够熟悉,以至于你的所有团队都将统一起来。期望一个JavaScript Web开发人员也能有效地使用Flutter和Dart进行开发,这绝非夸大其词。如果你相信我所说的话,那么由此可见,你的新统一团队的生产力将提高三倍。
代码维护
没有什么比修复一个bug并将其在所有客户端上都修复更令人满意的了。只有在非常特殊的情况下,使用Flutter生成的iOS应用程序中才会出现Android版本中不存在的bug(反之亦然)。在100%的这些情况下,这些都不是bug,而是外观问题,因为Flutter在其内置的Widget中遵循设备操作系统的设计系统。因为这些问题例如文本大小或对齐方式,所以在使用工程时间修复的背景下,它们是微不足道的。
面向JavaScript开发人员的Flutter
既然你在阅读CSS-Tricks,我敢打赌你是一位Web开发人员。如果你使用过任何当今最流行的框架(例如React、Angular、Vue等),那么你会很高兴知道学习Flutter是很容易的。
Flutter完全是反应式的,所以你习惯于在React中使用的思维方式和范式可以延续到Flutter中。你基本上是在构建大量的小型、可重用的组件(在Flutter中称为Widget),就像React一样。这些Widget包含完整的生命周期方法,并且是用类编写的。如果你在React中使用过这种语法
const MyComponent extends React.Component {
//...
render(){}
}
…那么你就能毫不费力地掌握Flutter。以下是在Flutter中执行相同操作的方法
class MyWidget extends StatelessWidget {
//...
build(){}
}
而且,就像React一样,Flutter更偏向于组合而不是继承。例如,如果你想在React中创建一个特殊的AddToCartButton
,你将在JSX中构建一个带有特殊功能和样式的按钮。这正是你在Flutter中执行的方式(除了JSX)。
最后,Flutter中的布局系统类似于我们熟悉的CSS规则,如flexbox和绝对定位。
不过,这也是Flutter创建视图的一个很大的区别。在Flutter中,从字面上看,一切都是Widget。有一些明显的、具体的Widget,比如Text
、Button
和AppBar
。但动画和布局声明也是Widget。要居中显示文本,你需要将Text
Widget包装在一个Center
Widget中。要添加填充,可以使用Padding
Widget。
想象一下,将一个React应用程序分解成你能创建的尽可能小的可重用组件。例如,如果你创建了一个高阶React组件,它只接受一个“padding”属性,并且它所做的只是将该填充量添加到嵌套在其内部的任何内容中。Flutter就是这样工作的,因为它没有CSS或标记。
在这张示例图片中,这里列出了一些你可能会用到的布局Widget,但用户无法“看到”它们

这看起来可能像是大量单调的工作,但Flutter内置了许多Widget(例如Padding
和Center
),因此你无需浪费时间自己去创建它们。
以下是一些最常用的Widget
- 布局 –
Row
、Column
、Scaffold
、Stack
- 结构 –
Button
、Toast
、MenuDrawer
- 文本 –
TextStyle
、Color
- 动画 –
FadeInPhoto
、转换 - 样式 –
Center
、Padding
总结
TLDR:你应该尝试 Flutter 吗?
如果你想用熟悉的方式创建流畅的移动应用,那么答案是肯定的!Flutter 完整地保留了性能和开发体验。它的动画以 60fps 的速度运行,并且内置了一系列 Cupertino 风格和 Material Design 风格的 Widget。或者,简单来说:Flutter 的开发效率惊人,并且没有牺牲原生性能。
如果你想今天就开始尝试 Flutter,这里有一些很棒的起点
Flutter 的文档是我见过的最好的文档之一,它们会教你所有你需要知道的知识。
为什么不选择 Xamarin 呢?
我在下面的几条评论中写了一个冗长的回复,但基本上——我是一名 Web 开发人员。在 Web 开发领域,React Native 非常流行,而 Xamarin 则不然。我接触它的机会太少了,无法发表意见,而且我对它了解不够,不敢轻易评价。
谢谢,Chris!又一次写了一篇很棒的文章!继续努力,伙计!
文章详细且写得很好,谢谢!
内容丰富,写得非常好。很高兴我路过这里,我马上就会尝试一下——我一直在关注 Native Script,这个听起来更好!
太棒了!我很高兴你发现这篇文章很有帮助。我承认我对 Native Script 一无所知,但我(显然)是 Flutter 的粉丝,我很高兴你打算研究它!
第一条评论说中了!你错过了 Xamarin。我很想知道你对 Xamarin 的比较意见。你还可以获得 UWP。
写得很好!如何在 Flutter 应用中管理状态?
Flutter 提供了许多选项——我建议访问http://fluttersamples.com/
该页面上的所有示例都是管理状态的不同方法。例如,它们有使用以下方法的示例:
我不明白为什么人们将 Flutter 与 React Native 进行比较,而实际的比较应该与 Xamarin 进行。您或其他人能否分享一些关于 Flutter 在内存速度或开发便捷性方面与 Xamarin 相比的表现统计数据?如果没有(对我来说)Flutter 就等于死路一条。
据我所知,很多人确实将 Flutter 与 Xamarin 进行比较,但我是一名 Web 开发人员——RN 在 Web 开发领域很流行,而 Xamarin 则不那么流行。
但对于你的问题,Flutter 在构建生产版本时会编译成原生代码——所以它和原生应用一样快。在开发过程中,它使用 AOT,因此它具有亚秒级的热重载,可以快速迭代。它还自带渲染引擎,因此你可以直接控制屏幕上的每个像素。这也使得它比 RN 和其他 JS 选项更快。
在我看来,文档很棒,工具也很好(适用于 VS Code 和 Intellij),社区也很棒。至于实际编写代码的体验:这取决于你的喜好。我喜欢它,因为它 100% 是 Dart 类——没有标记语言或样式语言。但这只是个人观点。
我对 Xamarin 一无所知,但经过一些简单的阅读,我可以告诉你,到目前为止,普遍认为 Flutter 是性能最高的跨平台选项。
好消息是,玩转 Flutter 非常简单。你可以访问 flutter.io,几分钟内就能上手。
好文章,Eric。你在管理层或技术概述层面出色地比较和对比了 Dart/Flutter 与 JavaScript/React Native。我同时使用过 RN 和 Flutter,我不得不承认,在我看来,Flutter 是跨平台移动应用开发的更优解决方案。感谢这篇文章。
感谢你的赞美,Michael。很高兴你喜欢它。
我的一点看法,一切听起来都很光鲜亮丽。我确实在考虑用 Flutter 编写我的下一个跨移动平台应用。真正让我犹豫的是——“简化方式”,关于 Flutter 中动画是如何实现的。当然,我不是 Dart 开发人员,但如果你在 YouTube 上看过 Flutter 的视频,你会发现编写一个元素的动画所需的代码量非常庞大。从前端/CSS 的角度来看,理解起来要困难得多。
你说的没错。从 CSS 转过来,Flutter 中的动画确实很难。当我开始编写 Flutter 应用时,也有同样的感受。我想,这都是权衡取舍的问题。
对于简单/常见的动画,我实际上认为它更容易。看看像 Hero 这样的 Widget:https://docs.flutter.io/flutter/widgets/Hero-class.html。Flutter 为你免费提供了很多东西。
对于不常见但简单的动画,我仍然认为 Flutter 通过 AnimatedWidget 类等功能简化了你的工作。
当涉及到复杂的动画时,可能很难弄清楚。我一直在为此而苦恼。权衡的是,你可以获得完全的控制权,并且性能更高。