🎨 使用 flutter 构建移动端 App
!本篇文章过于久远,其中观点和内容可能已经不准确,请见谅!~
想分享的是让你知道flutter
是一个非常不错的跨端解决方案,在开发效率、编程体验、表现力、流畅等方面表现很好,能够承载出色的产品的实现。但是如果你们的生产环境要求比较严格、需求有些极致,还是有很多问题要注意的,不过技术本身的发展趋势还是很值得期待的。
flutter
按照官方的定义是一个高性能、一致性的跨端 app SDK,关键词有跨平台、快速、高质量、漂亮、响应式,目标是构建出跨端的高性能应用。Flutter is an app SDK for building high-performance, high-fidelity apps for iOS, Android, web (beta), and desktop (technical preview) from a single codebase.
作为移动端的非常火热的跨端技术方案,与之前的跨端尝试不同,首先定位就是客户端的技术栈,没有采用 webView,也没有采用 JS 桥接方案,自行实现了一套 UI 实现方案,通过底层的跨平台绘图方案渲染界面。
跨端的技术栈,一致性和性能是比较重要的点。
高性能方面:flutter 和其他大前端跨平台有很多不同,没有 JS 语言的支持逻辑,不需要桥接的概念,直接二进制支持,性能和流畅度要好很多。
一致性方面:依靠跨平台Skia图形库实现跨端的功能,像素级别的一致性控制,能够保证相同的界面一致性。
前端的技术革新浪潮一直没有中断过,也一直用实践来补充新的能力,跳出前端之外的技术也看了很多的文章和订阅,
flutter
在我的阅读中出现了很多次,让我一直想要尝试这样一个跨平台方面还能兼顾性能的一个技术方案。flutter
最大的特点就是跨平台,尤其是目前客户端 Android
和 IOS
都要兼顾的场景,WebView
、Hybrid
、RN
、Weex
等尝试也都没停过,flutter
出色的性能,加上大公司背书,还支持嵌入原生模式等优点,成为了很多公司跨端开发的新选择。目前更是考虑了 web 和 桌面端的能力,前途无量。在公司新的业务设计中因为涉及到两端,开发工作量很紧张,作为前端能够提供的支持不多,所以我提出了主要的界面层使用
flutter
实现,而二三级的依赖底层能力的界面使用原生的技术,一方面分担很多的开发任务,另一方面能够不需要两套代码的繁琐。在花了点时间调研展示效果之后,团队决定采用这个方案。事实证明项目进度比分别开发好得多,效率能效很好,可以胜任生产环境。但是在实施的过程中,发现如果认为
flutter
就能一劳永逸的解决界面和业务还是 too young 了。PS: 很多的问题可能是自己的业务实践不足,而且遇到问题本身是促进解决方案变得更好的一个途径,结论是非常看好
Flutter
的应用前景,毫无疑问。技术本身没有优缺点,只是具体的应用有很多方面的不同,而且仅仅是我个人观点。
从跨平台方面来考虑,首先很自然的跟之前的 React Native 比较。RN 很久没有上手,目前的开发体验不知道怎么样,以我的旧经验来看。界面性能和开发体验比 RN 要好很多,响应、性能和动画很流畅,大列表的滑动非常丝滑,热重载很快等等,不至于让我有上手 RN 后,到处皱眉想放弃那种感觉。不过好像查资 RN 目前的性能和体验也有很大改进,具体这里不深入了。大厂的实践也能说明问题,Flutter 目前大厂里的口碑虽说有很多改进和问题,不过确实要好很多。
语言层面 Dart 语言要新学习,但是如果之前熟悉 JAVA、Typescript 或者 ES6+ 以及面向对象编程概念的话上手会很简单;代码组织和 react 有点像,响应式的组件化,甚至有很多理念很通用;UI 层面并没有很高的门槛,表现力很好,JSX 的火热一定程度也说明类似的开发体验还是很能被接受的。而且 Dart 线程模式、代码组织方式以及还算很完善的开发环境,让开发门槛都比原生要低一些。
可以说这是除了 js 让我最快上手的一个技术。访问官网(提供国内专版好评),下载或克隆一个 sdk,设置环境变量,flutter doctor 检测问题并给出详细说明,还给出修复命令,简直不能太小白友好,而且编辑器插件等支持也清楚明白,基本上网速没问题的情况,半个小时能把 demo 跑出来。
跑出一个可以交互的 counter 实例之后,鼓捣出多页面的复杂应用基本上修修改改就可以实现了,而且全都是组件化的思想,所以不需要考虑标记、样式之类的,抄上键盘开始垒代码就完了。
得益于 dart 新语言,逻辑、样式、布局都能在一个组件的粒度上聚合,开发者能够灵活拆分拼装,所以开发过程很流畅。再加上响应式的数据和界面绑定,实现一个功能和组件基本上分分钟能做到,这可比原生的开发灵活的多。有状态和无状态组件的预设足够简单,内置的 安卓和 IOS 默认样式的组件库足够搭起一个看起来很棒的 demo 应用。无论你之前有没有接触过组件化的抽象思考,上手之后,很容易从简单的按钮,到简单的页面,再到多页面复杂组件封装,一切都很自然。
得益于完善的接口能力、文档支持和代码补全,如果想要搭建一个简单 app,基础组件、路由、网络请求等等都有,稍微看下属性接口基本上就能写出来了。比如官方分别提供默认组件库,样式风格统一。而且整个官网的目的就是让你以最快的速度实现一个demo,而不是各种铺垫和基础概念,文档和接口感觉也是为了实现常见的app界面,很多常见的组件都被抽象到官方库,新手几乎不需要太深入的定制。而且还有 DevTools、Inspector、Performance、Profile、Memory 等工具帮助构建更高质量的代码。这样一个学习曲线对大多说人简直太友好,所以一个好的开发体验对一门语言的推广还是很重要的。
缺点部分分区前后期,前期比较多的缺点可能都是不习惯、不和谐,但是可以解决,最终能接受的。后期熟练之后,业务需求逐步复杂之后,慢慢的就会出现很多底层不稳定的地方。
整个项目是支持混合开发的,但是毕竟是一个不同的语言和渲染机制,没办法做到特别灵活。比如路由问题、共享数据资源问题、埋点监控、很多SDK等,涉及到原生部分的地方都或多或少不太和谐。比如业务安排是原生和flutter路由交错跳转,或者嵌入到原生中一部分,性能和体验会打折扣。毕竟一个 view 就是一套 dartvm,除非底层魔改。公司没有能力在这些问题上投入精力,所以一级界面都用 dart 来实现,涉及具体功能才回到原生中。这个不算大缺点,可以接受。
虽然现在发展迅速,社区活跃,但是不可否认还差很多,甚至比 RN 都差得远,但是毕竟这是一个 17 年才诞生的东西,很多需求没有特别多的社区解决方案,社区的包也有很多半成品,经常需要自己 DIY。当然现在 sdk 都还在高速迭代的过程中,这点没办法苛求,不过我相信社区活跃的情况下,很快就会欣欣向荣的发展。
现在发展太快,我认为官方迭代过程更看重的是填坑而不是统一,所以我在使用的过程中,组件本身没问题,但是用起来就非常别扭,比如基础组件各种属性莫名其妙,表意不明、组件各个属性很独立、样式和布局混用、matrial 和 cupertino 两个库很不统一等等,当然并不是大问题,就是用起来不太习惯。
最简单的一个例子,container 的 color 属性表示的是 decoration 的 color 属性引用,意思是容器背景色,不是 backgroundcolor 而直接用了 color 单词,css 用的多了会非常介意,同时样式是直接属性。text 组件的样式需要写在 style 里面,用 fontstyle 表示,其中有一个 color 属性表示文字颜色。icon 组件,color 却是一个直接属性,表示图标颜色。不同的组件属性表意可能根据组件设计最优,但是对于我可能觉得有一些奇怪,所以需要记忆的很多,有自动补全加上用的多了会好一些,但是初学者查表是不会少的。
这个不是语言本身的缺点,而是设计模式上的选择,类似的组件化都是这个样子的,各个组件类的嵌套变成了嵌套地狱,在 react 中,专门引入了 hooks 来用一层组件解决生命状态的影响。不过也可能是 react 的 render 比 flutter 的 build 更重,所以才显得嵌套很深不太好,flutter 这并没有那么影响。
Dart 有 JIT(Just In Time) 和 AOT(Ahead Of Time) 的编译模式。flutter 比 dart 有增加了很多编译模式,在 debug 下方便开发需要照顾到热重载和断点等,动态生成代码、调试 UI 等,使用类似 JIT 模式,所以很多的运行优化肯定会出现卡顿,在业务上了规模之后,路由两三层,十几个列表页面之后,低端机器就明显卡顿了,不过这也就是 debug 模式下热更新的折中不能苛求,只是些许的影响开发体验。
内存优化、长图片列表、多页面堆栈等问题,一般需要花很多时间处理,虽然其他开发也会涉及,但是这里涉及到原生的配合,所以调试体验不是很好。
上手门槛不高,但是用多了之后发现生态还有很多不足,浓浓的 JAVA OOPS 风格。与 TypeScript 生态相比,在语言设计上和生态建设上并不太好。不过 Dart 的版本迭代一直很快,都是建设中的东西。
这个之前一直觉得是一个非常好的优点,因为能够保证精力不至于分散到两个平台。但是深入之后,发现不仅仅需要懂得 dart,原生开发能力也是需要涉及的。而且各种环境问题、适配问题、平台差异真的有时候需要折腾,甚至你挠破脑门也不知道为啥。
崩溃率是有点高的,生产环境的应用,千分之几的崩溃率(跟代码质量、目标用户、业务类型都有关系)。这个对于用户量稍大的公司就是一个死刑了,毕竟万分之一的崩溃率才勉强能接受,我们在开发的时候也是遇到了很多奔溃的情况,虽然都能解决,但是还是有概率触发严重 bug,出现体验问题,而且都是偶发的,很难去调试。
上面说了这个生态目前并没有那么成熟,所以第三方支持不是很好,比如插件和库的选择,很多第三方的插件代码质量没法确保,毕竟很多都是验证性的方案,没有大量生产环境的验证,很容易出现问题。甚至经常会有需求变更的时候,需要修改第三方库,甚至转为内部维护。我们内部开发的时候,因为排期比较紧张,很多方案使用了第三方的,代码质量良莠不齐,一部分的实现需要魔改,或者添加边界条件才能适合我们的业务,代码质量有时候也是想骂人。不过最后的结果还是好的,都还算能接受。
在决定着手业务之前的调研阶段,已经见识了
flutter
在性能上是怎么媲美原生,吊打一众 frontend based frameworks
的,所以认为性能问题不至于成为瓶颈。但是在做了很多页面之后,发现性能还是出现了问题,卡顿问题也是需要专项解决。不过原生代码也需要考虑性能,这个不必多说,就是没办法再认同性能和原生能媲美,只能说还有很多能改进的地方。比如路由页面堆栈一旦比较多,而且都比较复杂的时候,页面依然会出现卡顿。
不过性能有问题,大部分确实做了很多的计算,开发上还是能够规避很多的这类问题的。
内存问题可能就比较普遍了,尤其是 ios 端。内存占用问题、内存泄露导致崩溃的有很多。优化方法也很有限,毕竟 flutter 作为应用界面绘制引擎,内存上没办法做的太干净。导致我一直怀疑 Google 的工程师是不是觉得内存的问题就从来不是个问题,Chrome 内存也是这个鬼样子,感觉电脑上喂了一个特别能吃内存的 Chrome 怪兽。
这个问题的解决很多也是业务层面的问题,比如业务中需要大量的图片,列表大概有几百张缩略图,快速滑动怎么提高性能。整个滚动列表里面图片组件的使用很可怕,flutter 自己有一套在 viewPort 外被强制回收的逻辑,而且加上组件的销毁和重建逻辑以减少内存的占用,仍然经常出现滑动多次、切换页面等操作之后内存就暴增,然后app崩溃。
为此真的花了很多精力尝试解决,可以查看 (flutter 性能优化)[./flutter-performance] 看下。
flutter 这个强大的存在也不是一篇文章就能说的明白的,优缺点也全都是我的自我理解,更何况现在也并不是我的主要开发语言,虽然非常感兴趣,花了很多时间做出来了产品,但是很多深入的东西没来得及 all in flutter,相信如果业务中这块加码发展了,肯定能发现更多好玩有趣的东西。我也非常看好 flutter 的发展,2020 一定在这方面尝试一些不一样的东西。
感谢您的阅读,本文由 Ubug 版权所有。如若转载,请注明出处:Ubug(https://ubug.io/blog/flutter)