在2017年,Google在Google IO开发者大会上公开发布了早期版本的跨平台移动应用技术Flutter。快进到今年的大会,官宣Flutter已经准备好投入生产环境,在九月底发布了Release Preview 2。这是其中一些亮点:

  1. 这个最新版本的主题是完美的iOS应用程序(之前主要关注Android的Material Design)。
  2. 减少应用程序的包大小,现在一个最小的Android应用程序在发布模式下只有4.7MB。
  3. Flutter自从开源以来,一直是GitHub上活跃排名前50的仓库之一。
  4. 大厂正在使用它,比如阿里(Android,iOS)、腾讯(Android,iOS)和Google广告(Android,iOS)。还有一个关于阿里巴巴如何使用Flutter构建闲鱼应用程序(Android,iOS)的视频,目前在中国有超过5000万客户在使用。
  5. 这张图显示了Flutter在Stack Overflow上得到了很多关注。

alt text

Flutter是什么

  1. Flutter是由Google开发的开源软件开发工具包(SDK),用于快速构建iOS和Android应用程序,并开源大部分代码。它与Android和iOS SDK配合使用,这也意味着你仍然需要一台macOS机器来构建iOS应用程序(就像你为React Native和Xamarin所做的那样)。对于我来说,安装Android版本非常顺利——我只需按照网站上的说明操作,并使用’flutter doctor’命令,但我最初在iOS设置方面遇到了一些问题。

  2. 它使用了由Google开发的Dart语言。是的,又是一个需要学习的语言,但别担心,如果你熟悉Java、JS、Kotlin、Swift或C#,那么它非常容易上手。

  3. 应用程序是预先编译为本地ARM代码的,而不是像React Native那样在运行时。这提供了更好的性能,因为没有中间的JS桥梁来解析和执行代码。但这也意味着没有通过在运行时下载新的JS代码束来进行OTA更新的选项。

  4. 它与React Native类似,也是基于“单向数据流”架构,或者说是响应式编程。简而言之,应用程序通过改变变量/属性(或者更通用地说,屏幕或视图的“状态”)来响应用户输入,然后根据新的状态重新呈现UI。函数不直接改变UI(按钮的颜色、标签的文本、列表的内容等)。

  5. 与React Native类似,Flutter也支持热重载。只需在代码编辑器中进行更改,保存,Android模拟器或iOS模拟器上的UI就会刷新。这是如此方便和快速,一旦尝试过就很难回去,它弥补了UI是以编程方式创建的,因此没有可视化编辑器的缺陷。

  6. Flutter可以通过第三方插件进行扩展,这些插件可以添加新的自定义UI组件或封装平台特定的功能,而这些功能不是内置类已经涵盖的(例如:视频/音频、货币化、存储、相机、增强现实、机器学习等)。这是我发现的最好的插件集合。有很多插件,但可能不是你所需要的全部。

  7. 与前面一点相关,Flutter通过在检查Platform.isIOS和Platform.isAndroid之后执行不同的代码(如果在你的.dart文件中,你想要实例化不同的UI小部件,或者逻辑不同),或者编写你自己的原生插件(如果你真的需要封装Flutter尚未提供的平台特定功能),来相对容易地编写平台特定的代码。

  8. 与第7点相关,对于典型的应用程序来说,性能不应该是一个问题(至少在发布模式下——调试模式明显较慢,因为它使用虚拟机来运行Dart代码),因为UI是由一个高效的底层C++库编写的,其他功能映射到它们的原生对应项。但是,必须注意的是:通过最小化重绘次数,并且仅重绘实际上依赖于已更改状态的部分。

  9. 你可以使用任何文本编辑器和flutter命令来编写和构建应用程序,但推荐的方法是使用支持Flutter插件的编辑器之一,即Android Studio、VS Code或Intelli J。这可以为你提供智能感知、自动完成、一些调试工具,免去了你需要使用命令行编译/运行应用程序的烦恼。

优点

  1. Flutter的UI绘制独立于平台特定原生组件的封装具有优缺点。优点是,如果某些内容在你的测试iPhone上以iOS 12的某种方式呈现,例如,它应该在任何其他iOS版本以及任何Android手机上以完全相同的方式呈现。而对于React Native或Xamarin,UI组件具有一些仅在一个平台或另一个平台上支持的属性,或者它们可能受支持,但在后台将其翻译为稍微不同的方式到它们的原生对应项。这意味着你要么需要在许多设备和操作系统版本上进行测试(并可能编写平台特定的代码来修复某些情况),要么只是知道它可能会在某些用户那里看起来不正常(或至少不同)。如果你在特定的OS版本上使用了不支持的属性或功能,你的应用程序甚至可能会崩溃。使用Flutter,你将更加安全(至少对于应用程序的UI部分来说)。你仍然应该在多台设备上检查应用程序,特别是如果你使用第三方插件,这些插件将映射到底层平台特定的原生组件。如果你使用诸如音频/视频、推送通知、应用内计费等功能,情况就会是这样。这个方法的负面影响将在文章的下一节中进行讨论。

  2. 热重载太有用了,这是开发者的梦想成真:在编辑器中按Ctrl+S,模拟器上的应用程序就在一秒钟内重新加载!告别了无尽的构建/等待/运行/等待/测试/重新开始的过程。实际上,当你改变资源和插件,改变导航、状态初始化或逻辑时,你仍然需要重新构建,但大多数UI更改都会立即应用到正在运行的应用程序中。对于UI密集型的应用程序,这是你将花费大部分时间的地方。

  3. 我喜欢小型可重用组件的整体原则,它们对“状态”变化做出反应,这也是React和React Native的核心思想之一。当然,也可以在纯iOS和Android开发中开发响应式应用程序,但使用Flutter(和RN)会更容易和更自然。这是因为它是技术的核心,而不是由第三方库提供并以几十种不同的方式实现的功能。

  4. Dart语言简单但功能强大且完整,可以与Swift、Kotlin或Java相媲美。使用async/await/Future进行异步编程非常简单。

  5. Flutter和Dart内置支持逻辑的单元测试和UI/交互的部件测试。例如,你可以发送轻触和滚动手势,在小部件树中找到子小部件,读取文本,并验证小部件属性的值是否正确。官方文档清楚地介绍了可用的内容。

  6. 我喜欢应用程序UI的每个方面都有主题化支持。创建我应用程序的浅色和深色主题中最困难的部分实际上是选择正确的颜色(我只创建了两个,但可以用相同的方法创建10个)。在代码方面,只需要几行代码(基本上设置根MaterialApp对象的主题属性)。

缺点

我必须说,我并没有找到任何值得列在“缺点”或“不足”部分的东西,但以下是一些在某种程度上并不那么好的事情,至少从某些角度来看:

  1. 正如已经多次提到的,Flutter以自己的自定义方式绘制UI,它不创建原生组件。它在复制Android的Material Design和iOS特定组件方面做得非常好,但在底层仍然不是原生的。这有一些影响,比如:
    (A)如果iOS 13改变了分段控件或UISwitch的呈现方式,那么你使用CupertinoSegmentedControl或CupertinoSwitch的Flutter应用程序在Flutter更新并重建之前将保持旧的外观。可以争论说很多用户不会在乎(我的大多数非技术朋友不会在乎,甚至不会注意到,例如,他们只关心应用程序看起来是否足够漂亮,而不是它是否与OS的纯净外观和感觉完全一致),但如果你是一个纯粹主义者,这可能是一个决定性因素。
    (B)如果你计划在现有应用程序的某些功能使用Flutter,你可能会看到原生部分和Flutter部分之间的差异。同样,这可能会让你的用户感到困扰或不困扰。对于纯Flutter的应用来说,这个问题就小得多了。
    (C)为了尽可能地简化开发过程,并假设你的用户不关心应用程序的原生外观,你可以只使用MaterialApp(它使用Material Design组件)并将其编译为Android和iOS。它将正常工作,尽管外观不是原生的,事实上这就是我为我的应用程序所做的。如果你真的关心这一点,决定在Android上使用MaterialApp,而在iOS上使用CupertinoApp,你将为UI大部分,如果不是全部的代码进行复制(这可能是你应用程序的一个相当大的部分),并且会使架构更加复杂。请认真考虑这一点,并决定是否值得这样做。

  2. 因为Flutter是更新的,并且拥有规模更小的社区,它远不及你可以在React Native甚至Xamarin中找到的插件丰富,但这就是目前的情况。选择有限,许多插件已经过时,不再维护,甚至可能不再与当前的Dart/Flutter版本兼容。一些组件(特别是非UI组件,映射平台特定功能)仅适用于iOS或Android,而不是两者(通常它们支持Android,因为Android开发者目前比iOS开发者更热衷于Flutter,因为Flutter来自Google)。然而,填补空白并为缺失的平台编写平台特定的代码仍然比从头开始好,如果Flutter继续变得越来越受欢迎,情况肯定会有所改善。

  3. 当出现布局错误(或其他低级错误)时,你得到的错误屏幕或日志可能会非常令人困惑和晦涩,因为它指向框架的某行代码,这可能是在你直接交互的许多抽象层之下。在原生iOS和Android上,错误通常更容易理解,如果不行,你通常可以将完整的错误复制粘贴到Google上,完全可以得到更多有用的链接来了解更多信息。由于社区仍然相对较小,Flutter的情况并不是如此。

  4. 在相同的.dart文件中(你的屏幕代码的位置)创建UI是简单直接的。这也意味着没有太多的分离。我更喜欢在单独的文件中使用标记代码创建UI(类似于在原生Android应用程序中所做的),而不是通过编程方式创建UI。

  5. 在Android上,绝大多数开发人员使用Clean Architecture和MVP(模型-视图-控制器)。在iOS上,它可以是MVC、MVVM(模型-视图-视图模型)或Viper。对于Flutter(以及React Native),感觉就像一切仍在定义中,没有“标准”或“几乎普遍接受”的架构方法。所有文章都显示简单的示例,这是正常的,因为他们仍然需要吸引人们,然后再谈论更高级的方面。然而,如果你计划将Flutter用于一个相当大的项目,那么最好有一个清晰的想法来构建它,这样它就可以随着应用程序的增长而增长,并且易于维护。再次强调,我绝对不是说Flutter不允许你构建具有清晰和可维护架构的应用程序,但只是说会涉及一些试错、实验和学习,因为它不像我们在原生iOS/Android应用程序中习惯的那样成熟和广泛使用。

总结

Flutter有很大的潜力,很容易入门并着手开发,并且有许多优秀的设计原则和思想。但是社区仍然很小,在跨平台插件方面还有一些缺失,或者在最好的情况下选择不多。此外,你必须接受这样一个事实,即你不会拥有一个100%原生外观的UI,并且如果你想要至少尽可能接近iOS和Android的UI外观,你的代码和结构将变得更加复杂。

就我个人而言,我认为这是一种非常有用的技术(已经可以使用了),适用于以下情况:

  • 你必须尽快地触及尽可能广泛的用户群 — 比如一家从零开始的初创公司,希望为两个平台发布。看看有没有一个或两个平台有动力,然后再投资更多,打磨东西等等。你可以把这看作是一个非常先进的原型,稍后可以进一步打磨,仍然保持在Flutter上,或者用一个本地版本和一个专门的团队替换。
  • UI本来就不是最大的关注点 — 例如企业/B2B应用程序,你希望有一款员工/客户可以使用任何类型的设备的业务应用程序,但并不太关心它是否与OS生态系统中的其他一切保持一致。这就是Groupon为其面向商户的应用程序所做的(但不是针对最终用户)。