1.1 移动开发简史
不知道有没有人统计过当今世界上还有多少人没有用过智能手机?这样的人非常少,目前几乎每人一部智能手机。从开发者的角度来看,一项技术的饱和程度莫过于此,在十年前智能手机和移动开发刚刚兴盛的那段时间,每个人都认为移动开发将是那个时代的未来,而很多开发人员当时顺其自然地投入原生(native)开发中。
原生开发通常是指针对某个特定的平台利用其提供的SDK和特定的工具进行开发。我们可以用Java或Kotlin调用Android SDK,开发Android应用,也可以通过Objective-C或Swift调用iOS SDK,开发iOS应用。Android SDK和iOS SDK在固定的平台上可以开发出性能功能强大的应用。另外,也可以通过系统提供的API访问手机的特定功能(相机、GPS等)。然而,当出现问题时,维护的成本较高,我们必须同时维护两套不同的代码,仅这一点就会使得大部分软件厂商难以生存。原生开发的动态化能力较弱,用户有时候势必须手动更新应用,这也带来了用户体验的下降。
针对原生开发带来的问题,后来的很多开发者选择在应用中嵌入WebView,也就是使用HTML5来替换一部分原生开发,从而使一套Web代码同时运行在Android和iOS两个平台上,而且获得了Web开发的动态特性。我们也将这种同时应用原生和跨平台两种开发方式的方案叫作混合(hybird)开发。但混合开发的不足在于难以调用系统级别的API,如果可以使用WebView提供的接口来实现通过JavaScript代码调用原生API的功能,那么WebView低下的渲染性能就是我们迫切要改变这种开发方式的强大动机,因为开发者知道这种方式始终摆脱不了Web浏览器渲染所耗的时间。
那么如何减少非原生UI在移动端渲染的耗时呢?React Native、Weex等响应式框架的跨平台方案随之而来,它们使用一种将非原生组件映射到原生组件并实现非原生代码与原生代码通信的技术(我们将它称为JavaScript Bridge)突破了这个瓶颈。图1.1展示了这种类型的响应式框架与原生平台交互的原理。
图1.1 ReactNative等响应式框架与平台交互的原理
由图1.1可知,这类框架的应用层与原生平台可以通过一个称为JavaScript Bridge的中间层交互,这样就能将原有的JavaScript组件转换为原生组件,同样,以这种方式在JavaScript侧使用原生平台的各种服务(如GPS、蓝牙等)。至此,跨平台方案已经成熟,我们的问题也相继得到了解决,开发者们开始热衷于对ReactNative社区的拓展并更加依赖该社区。如果读者对React方面的技术感兴趣,可以去深入了解,这对学习Flutter也有一定益处,因为Flutter的很多理念和思路来自React。
但经过更进一步的思考,似乎应用的性能问题依然没从根本上得到解决,以上提到的“将非原生组件映射到原生组件并实现非原生代码与原生代码通信的技术”便注定了这种方式永远不能使应用如原生应用那般流畅,因为我们无论在这一部分做多少的优化,始终都会存在通信转换的过程。如何消除这个过程?Flutter的创新性就在于此,它能够作为新一代跨平台方案的主要原因就在于它不依赖于原生组件。Flutter使用的Dart语言基于预(Ahead-of-Time,AOT)编译方式,这种编译方式在没有任何JavaScript Bridge的情况下就可以编译成平台原生的代码并直接与它们交互。另外,Flutter拥有自绘引擎Skia,Flutter与原生平台的交互方式如图1.2所示。平台层只需要提供一块画布(canvas),其他诸如手势、渲染和动画之类的任务可以由Flutter自身承担,这使得开发者拥有更大的控制权,并且能使应用的性能和原生应用几乎相等。这两个因素使通过Flutter开发的应用不需要任何转换过程就完全能够在原生环境下运行,并且可以直接与本机代码交互控制屏幕上的每个像素。
图1.2 Flutter与原生平台的交互方式