Flutter开发实例解析
上QQ阅读APP看书,第一时间看更新

1.1 移动跨端开发技术

Android与iOS是目前市场上最常见的手机操作系统,它们各自维护了一套技术栈与设计规范,采用完全不兼容的开发技术。因此,如果想开发一款能在两种系统上同时运行的应用,目前最普遍的办法是开发两遍。这会导致代码冗余问题,同时也导致人力成本翻倍。

移动跨端技术旨在解决这一问题,其理想目标是“一次编写,处处运行”,从而实现人效大幅提升研发人力成本降低的目标。当然,双端无法达到100%复用,对于实际应用,能做到大部分代码逻辑复用,少部分代码差异化实现,就能取得上述收益。

在下面的小节中,先介绍原生开发与跨端开发两个概念,之后介绍移动跨端领域的发展历程与难点。

1.1.1 移动端应用开发的一般流程

现实生活中有很多优秀的移动应用,给人们的生活增添了许多色彩。它们是如何被一步步开发出来的?移动互联网经过多年的发展,已形成了一套完整的研发方法论。

一款移动端应用从开发到上线,通常需要经过以下流程。

1 构思产品需求

对于一款移动应用,首先要思考该应用能够解决人们生活中的什么问题。发现问题后,再进一步思考如何解决,进而拆解出应用功能。最终确定整体产品形态,以产品文档的形式产出。

2 设计视觉界面

产品文档梳理完成后,需要转化为可在手机上操作的用户界面。设计师通过界面设计,确定应用包含的页面样式,并以设计图交互图等文档的形式产出。

3 制定技术方案

有了产品文档和设计文档,接下来进入开发阶段。研发人员根据产品、设计文档构思技术实现方案,其中可进一步拆解为后端技术方案、前端技术方案,并最终以技术方案文档的形式产出。

4 编程开发实现

确定了技术方案之后,可正式进入编程开发。研发工程师基于技术方案和产品、设计文档,进行分工合作,通过编程实现功能,将原本记录于纸面的产品文档、设计图最终变为可运行的应用程序。移动端开发者在其中主要负责前端移动端部分,后端开发者负责为后端服务开发程序,以及为移动端提供API接口。

5 测试回归验收

功能开发完成后,并不意味着功能就可以上线了。由于编程是一项复杂的工作,极易留下疏漏,即通常所说的bug。对于商业应用来说,bug是不可接受的,轻则影响用户使用体验,重则给公司业务带来经济损失。

为了确保功能质量,在互联网团队中通常会配备测试团队,会有专业的测试工程师对功能进行测试验收。测试工程师会将测试过程中发现的bug提交给研发人员,由后者进行修复,并交回给测试工程师进行再次验收。

6 版本发布上线

当测试验收通过后,说明质量已具备上线要求,接下来会进行发版上线操作。对于移动端来说,则构建出应用的正式版本,将其发布到应用市场。应用发布后,用户便能够通过下载升级,享受到新版本的功能了。

7 版本迭代更新

在实际开发中,通常会采取迭代开发的方式,即对应用的功能进行拆解,安排到一系列版本中,每个版本根据优先级开发一部分功能。

迭代开发是目前互联网产品常用的开发方式,通过迭代开发,产品能够尽快上线,抢占市场先机。同时也能够针对功能的有效性进行快速试错。

迭代过程如同“滚雪球”一般,很多移动互联网的商业神话就是从一个功能尚不完善的“小雪球”,逐步变大、变强,最终走向成功。

快速试错对于互联网产品是非常重要的,通常采用最小化可行产品(Minimum Viable Product,MVP)的思想,先以最低的成本快速上线一个功能,观察上线后用户的反馈效果,如果效果与预期一致,则通过后续版本持续完善。而如果未达到预期,说明方案有问题,需要重新思考产品需求。

1.1.2 原生开发与跨端开发

在移动端跨端领域经常见到原生开发跨端开发这两个概念,对于没有移动端开发经验的学习者来说有些陌生。在本节中介绍原生开发与跨端开发的概念、特点。

1 原生开发

原生开发指使用Android、iOS原生技术栈进行移动端应用开发。移动端设备属于移动嵌入式设备,最大的制约因素是电池和运算性能,由于电池容量是固定的,同时功率也限制了性能,在软硬件设计上都围绕省电进行。

因此,对于Android、iOS系统而言,传统Linux系统的进程调度、电源管理是无法满足的,必须要进行更细粒度划分。于是在Android中拆分出四大组件、建立生命周期概念,采用多种省电策略,比如应用切后台后会被系统挂起等。这些概念和框架的引入导致开发变得复杂,提高了入门难度。

Android系统由Google公司推出,是一款基于Linux内核的开源手机操作系统。在Android系统上,应用开发者使用Java、Kotlin语言进行应用开发,两者都运行在JVM虚拟机中,开发工具使用An-droid Studio。Android Framework提供了一系列Java框架与概念,比如著名的四大组件,Activity负责界面,Service负责后台逻辑,BroadcastReceiver负责事件广播,Content Provider负责数据共享。开发者基于这些API进行应用开发,整体架构如图1-1所示。

图1-1 Android系统架构

iOS由苹果公司推出,是一款基于Darwin内核的闭源手机操作系统,仅用于苹果品牌的移动设备。iOS使用Objective-C、Swift语言进行应用开发,开发工具为XCode,仅能在macOS下运行。iOS的整体架构与Android差异很大,定义了另一套概念体系,整体架构如图1-2所示。

图1-2 iOS系统架构

通过对比可以看出,Android与iOS两个系统的内核、系统组件、开发语言及开发环境均完全不同。对于传统移动端团队而言,通常由Android开发团队和iOS开发团队组成,对同一个应用需要开发两遍

重复开发的弊端前文已提到,会降低效率,并造成人力成本倍增。其实问题不仅如此,从编程角度来看,一个功能由不同的人开发两遍,由于各自对需求理解不同,以及两个平台的差异性,会导致最终实现出现不一致的问题。这是实际工作中一个比较棘手的问题,许多bug都滋生于此,甚至造成线上问题。

由此可见,传统原生开发存在低效重复劳动人力消耗问题。但在可靠的跨端技术出现之前,没有别的路可走,只能不得已而为之

2 跨端开发

跨端开发指用一套技术栈抹平不同系统之间的差异,基于跨端框架,开发者可以实现一套代码在不同系统上运行。

跨端开发并非全新概念,其历史非常悠久。如著名的桌面程序开发框架Qt,1.0版本发布于1995年。通过Qt能够实现程序在Windows、macOS、Linux下多端运行。

Qt的架构设计思想是首先设计一套独立于操作系统的上层框架Qt Framework,其中包含了Qt的各个核心模块,如QApplication、QWidget、QThread等。这些模块都是操作系统无关的,Qt的UI层选择独立绘制,没有使用操作系统提供的控件库。这种设计思想具备良好的可移植性,各种操作系统只需要提供底层能力进行适配即可。Qt的整体架构如图1-3所示。

需要强调的是,与上一节中给出的操作系统架构图不同,跨端框架运行在操作系统之上

Qt取得了巨大的成功,至今已发展成为一套完善、成熟的桌面跨端技术方案,成为跨端开发框架典范。

除了Qt之外,Web技术也是一种跨端技术。不论使用哪种操作系统,只要安装浏览器就能够访问网站。一个基于Webkit内核的浏览器的架构如图1-4所示。

浏览器架构与Qt存在一定的相似性,都是通过封装一套统一框架,在框架之上运行应用。但Qt应用通过C++开发,用户需要先安装软件才能使用,而浏览器使用Web技术开发,即HTML、CSS和JavaScript,它们都具备动态性,可以随网络下发运行,用户只要输入一个网址就能访问网站,强大的动态性促成了互联网时代的繁荣。

图1-3 Qt架构

图1-4 浏览器架构

1.1.3 移动跨端开发技术的发展历程

随着移动互联网时代的到来,Android和iOS成为市场上最流行的两种操作系统,在前文中讲到,由于两种系统采用不同的开发技术,开发成本较高,因此出现了移动端跨端开发这一技术领域,并诞生了多种跨端方案。

1 基于网页的跨端方案

Android和iOS均提供WebView容器,它允许在应用内嵌网页。浏览器本身是一种非常优秀的跨端方案,因此移动应用通过使用WebView便能够具备跨端能力。

这种移动跨端方案是最早采用,也是目前最广泛采用的一种方案,绝大多数移动应用都会集成这一能力。由前端开发者进行网页开发,移动端通过WebView展示。由于前端开发本身效率高于原生,并且双端只需开发一遍,因此大大降低了研发成本。

这是不是意味着,只要Android、iOS两端提供一个WebView壳,整个应用都是用前端网页开发,就完全解决跨端问题了?答案并不全是,这种方案的主要限制在于性能与体验

浏览器的执行效率是远低于原生应用的,尤其在性能较低的手机上,这导致一些复杂的交互效果不够流畅,或出现卡顿掉帧的情况。同时,由于浏览器是一个沙箱环境,无法访问到所有系统原生能力,因此一些与系统深度交互的功能是难以实现的。还有一点,打开网页需要联网,存在加载等待时间,无法像原生页面那样立刻展示视图。

如果想打造一款效果丰富、体验流畅的移动应用,通过网页套壳方案往往无法满足,此时需要原生实现。但是如果是开发一些对体验要求不高的应用,如商务流程表单类应用,这个方案是比较适用的。

在实际的移动应用开发中,通常采用两者混合的方式,对交互复杂、体验要求高的页面使用原生开发,对一些对体验要求不高的页面使用网页开发,在体验与成本之间实现一个平衡。

同时,由于网页天生的动态性,对于一些经常发生变动的页面,比如活动运营页也通常选用网页方案进行实现。

2 React Native

React Native是一款由Facebook推出的著名移动跨端方案,与Flutter一样,也是目前最热门的方案之一。React Native的特点是以前端的开发方式开发移动端,它基于前端React框架,用JavaScript或TypeScript语言进行开发,最终渲染成原生移动端组件进行展示。

与网页方案对比,同样是前端开发,React Native不依赖浏览器,而是桥接到原生渲染,因此执行效率大大提升。同时它也允许通过NativeModule方式将系统原生能力导入到React Native中,还允许通过UIManager的方式将原生的视图进行包装,导入React Native中使用。

React Native一经推出迅速走热,成为最近几年移动端跨端的主流方案。通过多年发展,React Native不断完善,形成了庞大的开源社区,拥有众多高质量开源库,成为一套完备的跨端解决方案。

React Native采用JavaScript语言,在iOS上使用系统内置的JavaScriptCore引擎,在Android上由于系统没有内置JavaScript引擎,因此React Native会在应用包中自带一个JavaScriptCore,这会导致Android安装包变大的问题。

虽然React Native性能较网页方案有很大提升,但运行效率仍低于原生开发。首先JavaS-cript是一门脚本语言,执行效率比原生慢,同时从JavaScript桥接原生也存在性能开销。另外JavaScript引擎运行也需要占用内存,因此React Native应用的内存开销也要高于原生。

值得一提的是,React Native目前也处在快速发展中,并且吸引了微软等巨头参与。针对上面提到的缺点,React Native新版本完成了多项改进,比如换用自研的Hermes引擎提升运行效率、降低内存,以及正在进行中的新架构重构,包含多项重大改进(如JSI对象映射机制、Fabric视图层重构,以及TurboModule更加高效且可同步、可异步的原生能力调用)。

1.1.4 跨端技术难点

经过前面的介绍与对比,可以总结出跨端方法存在以下技术难点。

1 双端一致性

一套代码在多端得到一致的展示效果是跨端方案的基本要求。基于网页的方案通过成熟的浏览器技术,能够保证较好的一致性。

对于渲染到原生视图的方案来说,难以做到完美的一致性。原因在于这些方案最终渲染出来的还是Android、iOS的原生视图,由于双端原生视图的实现原理不同,因此总有一些细微之处是难以对齐的。加上Android、iOS系统会不断升级,原生视图的代码实现也会有变动,需要额外的工作量进行对齐。

2 运行效率

运行效率也是跨端方案的一个重要考量因素。基于网页的跨端方案由于效率不够高,无法用在注重使用体验的核心页面上。React Native这类框架舍弃了浏览器,仅保留JavaScript引擎并渲染到原生,相较于网页跨端运行效率大大提高。但是因为JavaScript是脚本语言,本身运行效率低于原生,加之从JavaScript渲染到原生需要进行桥接,在Android上需要经历从JavaS-cript到C,再通过JNI到Java的连续跨层,存在一定的性能开销,因此运行效率还是大幅慢于原生。

3 开发效率

许多人会将运行效率与开发效率混淆,两者实则是不同的概念。运行效率高指的是这个框架“跑得快”,从而能够胜任更多复杂页面。开发效率高指的是“开发速度快”,决定了研发效率的高低。

众所周知,不论Android还是iOS原生开发的效率都是比较低的。引入一套新的跨端框架,开发效率就一定比原生开发要高吗?答案是不一定。

首先,跨端框架能够以一套代码在多端执行,从而避免开发两遍,从这一点上来看,开发效率一定是提升的。

但还有一个问题,跨端方案同时也带来了其独有的开发方式。对于一个跨端框架来说,如何保证新的开发方式比原生开发效率要高,这也是一个重要问题。

开发效率体现在多个方面,在开发阶段包括开发框架的易用度、开发语言的学习曲线;在调试阶段包括调试工具链的完善程度;在构建阶段包括应用打包构建的难度、与原生工程结合的难度。除此之外,开源生态及开发社区的完善度都对开发效率有影响。

回顾成功的跨端框架,它们都是具备了极高的开发效率。Web开发使用的CSS/HTML/JavaScript,俗称“三剑客”,开发效率极高。React Native则基于React框架,同时复用部分Web技术,也实现了较高的开发效率。

4 原生能力导出

对于跨端框架来说,如何对两个系统能力做整合也是一个难点。Android和iOS两个系统的原理有差异性,同一种原生能力在两端有着不同的实现。因此跨端框架需要提供一种机制,能够分别对两端进行封装,并向上提供一套统一的接口。

对于网页跨端来说,通常使用JSBridge的方式进行导出,功能较弱。React Native通过NativeModule/TurboModule的方式,导出的能力更加强大,并且能够以库的形式复用,在React Native庞大的开源生态中,提供了多种多样的扩展库,供开发者快速接入。

5 动态性

原生开发采用应用商店发版升级的模式,必须经过应用商店审核、用户下载的发布流程,导致无法随时更新。这一点比Web发版要慢很多,Web可以实现随时发版,用户再次打开网址即可访问新版本网页。

网页跨端方案为原生开发带来了动态性,在业界流行的开发实践中,通常将应用中如运营活动这种频繁变更的页面用网页实现,保证营销活动快速上线。React Native也支持动态化,它的构建产物是JavaScript Bundle,可以实现Bundle联网更新,从而实现动态化。

动态化其实并不是跨端方案必须支持的特性,但是由于网页跨端和React Native等主流方案都支持动态化,并且动态化是移动开发中的一个核心痛点,因此在移动跨端领域一般也将动态性作为考量的一个方面。

6 包体积

用户对应用的安装包体积也是比较敏感的。如果安装包较小,用户在使用流量上网时也更愿意下载安装,从而有利于积累用户。同时,用户的手机容量往往有限,当手机空间出现不足时,用户通常会删除那些占用空间较大的应用,一旦删除很可能会流失此用户。

对于网页跨端方案来说,由于WebView在Android、iOS中都是系统自带控件,并且内容动态下发不会增加安装包体积。对于React Native,在iOS下复用系统的JavaScriptCore引擎,因此安装包不会有明显增大,但在Android上需要将引擎内置到安装包中,会导致包体积增大。React Native新版本中换用了Hermes引擎,这个问题得到了一定的缓解。