如何评价 Google 的 Fuchsia、Android、iOS 跨平台应用框架 Flutter?

其中,Fuchsia 的官方应用框架就是 Flutter + Dart 。
关注者
2,175
被浏览
423,246

58 个回答

我在过去做过若干年的动态化技术的开发,也写过类似于 RN 的应用框架(但要早于 RN)。简单从几个角度对比下 Flutter & RN/Weex,顺便聊聊动态化技术:


当前几大动态化技术对比

  1. 性能和体验
    Flutter 由于渲染的基础(gdi)是自己实现的,所以实现跨平台、性能优化、摆脱平台约束方面的裕度更大。从实际体验来看, Flutter 的性能比 RN 要高不少。

    我尝试总结下性能差异的原因以及 Flutter 架构上为“未来”留下的裕度:

    运行时语言:从前端的思维来看,jsx 或 dart 都是一种声明式的写法,但 jsx 需要转译(工程上看起来美好的东西肯定是需要在别的方面消耗更多),dart 是直接语言层面支持了 node tree 的书写,且对象创建成本低,可直接编译成 native 代码(AOT),VM 效率更高。运行上应该是 dart 效率高很多。

    渲染机制:RN 是从前端思想出发的框架,其在表达复杂 UI 时需要依赖前端“盒子”的深层次叠加嵌套,在 RN 背景下,这每个“盒子”都是一个 native 的 view,这时候就相比 native 开发来说多了很多 view 对象,造成了性能降低。也就是说复杂 UI 需求下,RN 对 UI 的表达效率远低于 native 造成性能低下(Facebook 后来做了一个项目 litho 的亮点就在于打平布局层次,针对性优化我说的布局表达效率低下这一点)。Flutter 是基于 skia (gdi) 层面往上去做的,每个 node/布局是否一定需要是一个 layer 以及 render tree 怎么来划分和实现都有更多灵活性和性能优化的空间,所以能做到性能更优。

    组件的兼容性:
    Flutter 提供的 widget 都是基于 skia 来实现和精心定制的,与具体平台没关,所以能保持很高的跨 os 跨 os version 的兼容性。
  2. 跨平台
    RN 是一套概念/设计理念跨越两个平台,具体到实际平台上去还要去适配和桥接差异性(这其中有巨大的工程成本和性能牺牲,比如做动画,js 就绝对不能用,用了性能就差了)。Flutter 至少做到了一套代码(不涉及平台 api 层面的 UI 及纯事件响应可以完全一样)。
    Flutter 相对来说是做到了跨平台。RN 更适合称为:将一种设计理念延展到两个平台,不能称其为“一套代码,自动部署多平台”的跨平台方案。
  3. 对未来的适应性
    由于 Flutter 从更基础的层去抹平平台差异,Flutter 站在了更宽广、更可控的一个基础平台上去演变和发展。RN 永远需要 follow native 开发的这套约束,桥接和抹平差异乃至应用层去适配的成本、面对具体场景去优化性能所需要的成本都是居高不下的。RN (动态化当然是首要好处,这是这份回答的隐含前提)属于“大公司扛大旗,赚吆喝,小公司跟着复用下现有资源”。
  4. 动态化技术的未来
    我个人认为 RN、weex 这类设计都是走不远的,为什么,动态化技术最成熟的就是 H5/Web,真正产业化(标准化、研发支撑、上下游软件开发商、开发者生态)的技术栈还是 H5/Web。所以业界(软件公司、开发团队)对于动态化技术的期待就是 H5,H5 是要由浏览器来支撑的,RN 的能力不到浏览器的 5%(举例 index = 1000,绝对布局,各种动画和复杂布局能力很难用 native 来实现,还有各种布局模型、浮动元素、css rule,不一而足。举例:本人曾经跨 Android、iOS 对等的实现全规范 css 中的渐变色,开发测试花了 2 天,可能还有未知的 bug),RN、Weex 是无法满足这个期望的(面对一个复杂点儿的需求,RN、Weex 都需要 case by case 去 review,还可能需要写 native 代码去扩展才能实现;而 H5 保证了 99% 概率下都是可以实现的。不需要产品/业务将就“技术”)。

    对于工程而言,RN、Weex 这类方案最大的价值就是提供了一套让传统前端开发上手 native 开发的途径,同时创建了一个社区用于存放可供复用的组件库,让小公司、小团队能共享这部分“生态”,且能切实实现“命题作文”类的需求。
  5. 研发模式
    Dart 语言相关的 vm、debug 以及 hot reload 都是 Google 官方开发和支持的,是其老本行,Flutter 也定位于未来的跨平台的应用框架,更是 Fuchsia OS 的正统 app framework,以上是定位;其次本人跑过 Flutter app 的 demo,研发体验上还是很 “敏捷” 的,实现了现代化框架的 “所改即所得”。
  6. 结论:Flutter 从设计、体验、跨平台上都有亮点。值得关注和寄予期望。但目前成熟度有限,不适合商用;不做改造的前提下,不具备动态化能力(release 版本 dart 被编译后再分发)。

--- 2018/7/1 更新

现在闲鱼已经在做基于 flutter 的线上实践,可以参看:


目前闲鱼的实践中是拿到了 flutter 在性能、开发效率方面的好处,但是降低包体积、动态化还没有实现。


畅想 Flutter 如何实现动态化

  1. 将 AOT compiler 的能力放到客户端,就跟 android art runtime 下第一次安装 apk 时 aot 编译一次一样,这样 flutter 程序可以以 script 的形式动态分发,同时运行时又能得到 machine code 的性能优势。
    挑战:AOT compiler 很大很重,移植到移动端运行有可能不可行。

2. framework 部分用拥有巨大生态的 JavaScript 等动态语言重写(主要是 widget/layer/renderobject 相关的布局/动画/渲染/语义(aka. 可访问性)计算、任务调度),复用现有 flutter engine(c++ 实现) 部分

挑战:js 写渲染逻辑/动画性能低下,支持灵活的任务调度能力差


flutter 的核心黑科技有哪些

  1. dart
    dart 语言对于 flutter 众多功能层面的特性做出了全方位、多角度的支撑,除了生态小不太容易推广外,dart 完美匹配移动端“轻”且“快”的技术要求。

2. 渲染机制
google 由于有 chromium 项目的积累,所以渲染这块是手到擒来。
代码一开篇就把 layer/renderObject/displayList/layout (源于 WebKit )这一套渲染给熟练的弄过来了。对了,这一套渲染还在 Android 系统上用着。

flutter 的核心不足

  1. dart 语言的生态小,精通成本比较高
    dart vs javascript,javascript 有一个定律(本质:无处不在、网络效应)很难被其他语言打败:

    如果某个软件能用 javascript 实现,那么最终它一定会用 javascript 实现。

    说到 dart 这个舶来品,在国内更是难以推动,typescript 之于 javascript 算是同门师兄弟,相对迁移难度不高,但 dart 之于 javascript 语法和概念上差异巨大,再加上英文文档、社区、样例代码的缺乏,在国内基本上没有流行的希望。

    结论:要想在国内速成蔚然成风的环境下流行的技术,必须是像 thinkphp 这样全中文文档,样例代码丰富,论坛 24h oncall 的技术,简言之要像柳永的词:“人人皆能歌柳词”。
  2. 嵌入外部 platform view 成本高
    这块(基于官方代码)目前在 iOS 端有支持,android 上还没有,但相关开发者博客上有提到实现了 webview//mapview 等 platform view 的嵌入。
    从 iOS 端的实现来看,每嵌入一层 platform view 会额外多一层 surface,内存代价比较高。

3. 平台 API

flutter 目前提供的开箱即用的功能只有 UI framework + dart 语言的能力,平台能力需要通过 platform channel 来扩展。当然这一点也是除了 RN 等其他同类解决方案的通病。

注: flutter 被 google 定位于跨平台、跨环境的应用开发框架,单一从动态化框架的角度去评价和衡量也有点牵强。

4. 兼容性 & 完备性

使用 Surface 这种平台级重量资源,[Android平台]其申请释放都是异步的,很可能有很多的兼容性问题。同时粒度上无法让已有 native view 作为 host(比如 ListView),一个小的 flutter 放进去做个 cell,并且彼此之间复用。此处完备性定义为:普适各种使用场景

未来的动态化技术

不论是 RN 还是 Flutter、Weex 都只能解决一部分问题,世界上成熟的产业级标准只有 Web 和 Native,所以站在 RN Flutter Weex 不能通吃所有场景所有需求的这个前提下,讨论下什么样的动态化技术能走得更远,生命力更长久:

  1. 设计和实现简单轻量
    设计和实现简单、轻量的东西才经得起迭代和扩展,才有生命力
    平台原生的一定是最好的,不要拒绝它,要拥抱它

    核心两件事:
    1.1 轻量级桥接 JS,实现跨端复用代码,开发队伍上让前端同学能介入,同时也是应用能动态性(分发)的基础
    1.2 跨平台统一抽象应用框架、组件、模块、扩展机制...,抹平平台差异
  2. 定位于补充 web,而不是取代 web
    定位大了,搞不赢浏览器,同时会把自己拖死
    定位大了,每个点上都没有超常的亮点,靠覆盖面取胜的东西最终胜不了

    谢谢大家的关注,后边要是有精力,我会基于本人实现的在商用程度和用户量上高于 React Native、且上线早于 React Native 的动态化引擎来展开:

    如何设计一个动态化引用引擎,未完待续。

试用 Flutter 一段时间了,有几点简单的感受。

首先我认为 Flutter 的定位是要比 React Native 高的,毕竟在不久的将来发布的 Fuchsia OS 就钦定了 Flutter 作为 UI Toolkit。即使 Flutter 具有跨平台开发能力,但我不认为它能替代 iOS 的 UIKit 或者在 iOS 开发领域占一小杯羹,毕竟 Cocoa 和 UIKit 有太多的东西不可被替代。而 Android 完全可以用 Flutter 去取代,因为 Android 现有的 UI Toolkit 我认为比 Flutter 差得太多,Flutter 更优秀,而且就是为 Material Design 设计的。

再谈与 RN 的区别,从开发体验上来说,Flutter 的范式与 React、RN 非常类似,都是在状态变更时重新构建 Widget Tree,Flutter 底层再将 Widget Tree 转化为更适合渲染的 Render Tree 交给操作系统去渲染。React Native 也是用 \tt{React.Component} 去表达一个抽象的视图,然后内部转换为平台相关的对象(Android 为 \tt{View} ,iOS 为 \tt{UIView} )。唯一的区别就是渲染层,React Native 使用的平台相关视图对象就会有平台的局限性,比如 \tt{UIVisualEffectView} 并不是跨平台的, \tt{CALayer} 的阴影属性不是跨平台的,RecyclerView 也不是跨平台的,这就会造成同样一份 RN 代码会最终渲染出来两套不一样的 UI,因为平台特性的差异,甚至有时候需要写两份代码,并不能做到『Write once, deploy everywhere』。而 Flutter 这一点做得就非常好,那就是用自己的渲染引擎去渲染界面,自己想用 Skia 就用 Skia,想用 Metal 就用 Metal,总之两个平台最终的效果可以做到完全一致。而且 Flutter 的性能非常好,完爆 React Native,这一方面有语言的关系,另一方面也是因为 Sky Engine 的优秀性能。

Dart 是整个框架争议最大的部分,使用 Dart 作为唯一开发语言这个事实一开始我也是不能接受的,毕竟在用 Flutter 之前我从来没接触过 Dart,甚至都没怎么去过它的官网。但实践证明 Dart 上手也非常快,不亚于我第一次用 Kotlin。看官方文档学一下只需要半天时间,你就能写出比较常规的 Dart 程序了,包括 \tt{async} 、迭代器等的使用。但可能是由于 Dart 的语法设计,用它来写嵌套 Widget Tree 非常不友好,代码很丑,经常就造火箭了。但另一方面 Dart 中传参方法貌似又是为 Flutter 设计的,构造对象很方便。Flutter 使用的 Dart SDK 是阉割版的,比如缺少 mirrors 包,啥,你告诉我在 Dart 里不能用反射了?最后,编译型语言 + 强类型加分,当然你想用 dynamic 谁也不拦着你。其实这些都不是问题,最令我担心的是 Dart 的生态,不像 Kotlin,都是 JVM,但 Dart VM 下类库数量我表示不敢恭维,这就要看以后的发展了。也许以后还是免不了写一些 C++、Java 代码。

最后表个态,我还是很看好 Flutter 的。