作者:个推iOS工程师 伊泽瑞尔

一、背景

目前,移动开发技术主要分为原生开发和跨平台开发两种。其中,原生应用是指在某个特定的移动平台上,使用平台所支持的开发工具和语言,直接调用系统提供的API所开发的应用。 原生开发的主要优势体现在: 1.可以快速访问本平台的全部功能,比如摄像头、GPS等; 2.原生应用的速度快、性能高,而且可以实现比较复杂的动画和绘制效果,用户体验较好。 原生开发的缺点也很明显,主要体现在: 1.开发成本较高,不同的平台必须维护不同的代码,人力成本也会随之增加; 2.有新的功能需要更新时,只能进行版本升级。 随着移动互联网的高速发展,在很多的业务场景下,传统的纯原生开发已经不能满足日益增长的业务需求,主要表现在以下两个方面: 1.应用动态化的需求增大。当需求发生变化,或者是需要增加新的功能时,传统的纯原生应用开发只能通过版本的升级来更新内容,然而应用的上架和审核都需要一定的时间。因此,开发人员迫切地希望进行应用内容的更新时,可以不更新版本,提升工作效率。 2.业务需求变化快,开发成本变高。原生开发一般需要技术团队对iOS、Android两个开发平台进行维护。当版本更新迭代时,开发和测试的成本都会增加。 针对上述两个问题,跨平台框架应运而生。

二、跨平台技术简介

针对上文提到的原生开发所面临的问题,目前在IT界已经诞生了很多跨平台框架,主要分为三类: 1.H5+原生(Cordova、Ionic、微信小程序); 2.JavaScript开发+原生渲染(React Native、Weex、快应用); 3.自绘UI+原生(Flutter)。 在本文中,我们将对React Native、Weex和Flutter进行对比。 1.React Native React Native是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook开源的JS框架React在原生移动应用平台的衍生物。React Native使用了react的设计模式,但是其UI渲染、动画效果、网络请求等均是由原生来实现的。开发者编写JS代码,通过React Native的中间层转化为原生控件,并进行操作。也就是说通过JS代码来调用原生的组件,从而实现相应的功能。 React Native实现跨平台的功能,主要由Java、C++和Javascript三层所构成的。其中,C++实现的动态链接库(.so),作为中间适配层桥接,实现了JS端与原生端的双向通信交互。React Native会把应用的JS代码编译成一个JS文件,React Native整体框架目标就是为了解释并运行这个JS脚本文件,如果是JS扩展的API,则直接通过bridge调用native;如果是UI界面,则映射到virtual DOM这个虚拟的JS数据结构中,通过bridge传递到native,然后根据数据设置各个对应的真实native的View。  2.Weex 在Weex设计之初,开发者就考虑到,使其能够在三端(iOS、安卓和H5)上均能得到展现。在最上面的DSL,阿里一般称之为Weex文件(.we),通过Transform转换为js-bundle,再部署到服务器,这样服务端就完成了。在客户端,第一层是JS-Framework,最后是RenderRengine。  如上图所示,Weex的输入是Virtual DOM,输出是native或H5 view,还原为内存中的树型数据结构,再创建view,把事件绑定在view上,设置view的基本属性。Weex Render会分三个线程,不同的线程负责不同的事情,让JS线程优先保障流畅性。

表面上,Weex是一种客户端技术,但实际上,它串联起了从本地开发、云端部署到分发的整个链路。开发者可以在本地像编写Web页面一样先编写一个APP界面,然后通过命令行工具将之编译为一段JavaScript代码,生成一个Weex的JS bundle。与此同时,开发者可以将生成的JS bundle部署至云端,之后通过网络请求或者预下发的方式加载至用户的移动应用客户端。 在移动应用客户端,Weex SDK会准备一个JavaScript执行环境,在用户打开一个Weex页面时,在该环境中执行相应的JS bundle,并将执行过程中产生的各种命令发送到native端,进行界面渲染、数据存储、网络通信、调用设备及用户交互响应等。如果用户希望使用浏览器访问这个界面,那么他可以在浏览器中打开一个相同的Web页面,这个页面和移动应用使用相同的页面源代码,但被编译成适合Web展示的JS Bundle,通过浏览器里的javaScript引擎及Weex SDK运行起来的。 3.Flutter Flutter 是Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过Dart语言进行APP开发,只需要一套代码就可以同时构建Android和iOS应用,并且可以达到与原生应用一样的性能。Flutter还提供了丰富的组件、接口,开发者可以高效地为 Flutter添加native扩展。此外,Flutter还使用了Native引擎渲染视图,为用户提供了良好的体验。 Flutter与用于构建移动应用程序的其它多数框架不同,因为Flutter既不使用WebView,也不使用操作系统的原生控件。相反,Flutter使用自己的高性能渲染引擎来绘制widget。这样不仅可以保证在Android和iOS的UI一致性,而且也可以避免对原生控件依赖而带来的限制和高昂的维护成本。 同时,Flutter使用Skia作为2D引擎渲染,Skia是Google的一个2D图形处理函数库,在字型、坐标转换以及点阵图等方面都有高效而且简洁的表现。Skia是跨平台的,并提供了非常友好的API。由于Android系统已经内置了Skia,所以Flutter在打包APK时,不需要再将Skia打包到APK中,但是iOS系统并未内置Skia,所以在构建API时,必须将Skia一起打包。

三、高性能的Flutter

目前,Flutter程序主要有两种运行方式:静态编译与动态解释。静态编译的程序在执行前,会被全部翻译为机器码,通常将这种类型称为AOT,即 “提前编译”。解释执行则是一句句地边翻译边运行,通常将这种类型称为JIT,即“即时编译”。 AOT程序的典型代表是用C/C++开发的应用,它们必须在执行前编译成机器码。而JIT的代表则非常多,如JavaScript、python等。事实上,所有脚本语言都支持JIT模式。但需要注意的是,JIT和AOT指的是程序运行方式,和编程语言并非是强关联的,有些语言既可以以JIT方式运行,也可以以AOT方式运行,如Java、Python,它们可以在第一次执行时编译成中间字节码,然后在之后的执行中,直接执行字节码。 Flutter的高性能主要靠两点来保证,首先,Flutter APP采用Dart语言进行开发。当Dart在 JIT模式下时,其运行速度与 JavaScript基本持平。此外Dart支持 还AOT,当Dart在 AOT模式下事,其运行速度远超JavaScript。速度的提升对高帧率下的视图数据计算很有帮助。 其次,Flutter使用自己的渲染引擎来绘制UI,布局数据等由Dart语言直接控制,所以在布局过程中不需要像RN那样要在JavaScript和Native之间通信,在一些滑动和拖动的场景下具有明显优势。由于滑动和拖动往往会引起布局的变化,所以JavaScript需要不停地与Native之间同步布局信息,这和在浏览器中要JavaScript频繁操作DOM所带来的问题是相同的,都会带来比较可观的性能开销。

四、为什么Flutter会选择Dart语言?

1.开发效率高。

Dart运行时和编译器支持Flutter的两个关键特性的组合,分别是基于JIT的快速开发周期和基于AOT的发布包。基于JIT的快速开发周期:Flutter在开发阶段,采用JIT模式,这样就避免了每次改动都需要进行编译,极大地节省了开发时间。基于AOT的发布包,Flutter在发布时可以通过AOT生成高效的ARM代码,以保证应用性能。而JavaScript则不具备这个能力。

2.高性能。

为了实现流畅、高保真的的UI体验,Flutter必须在每个动画帧中都运行大量的代码。这意味着需要一种既能支持高性能,又能保证不丢帧的周期性暂停的语言,而Dart支持AOT,在这一点上比JavaScript更有优势。

3.快速分配内存。

Flutter框架使用函数式流,这使得它在很大程度上依赖于底层的内存分配器。 **4.类型安全。**由于Dart是类型安全的语言,支持静态类型检测,所以可以在编译前就发现一些类型的错误,并排除潜在问题。这对于前端开发者来说更具有吸引力。而JavaScript是一个弱类型语言,这也是为什么在诸多前端社区中,会有众多为JavaScript代码添加静态类型检测的扩展语言和工具。

五、Flutter框架结构

Flutter Framework是一个完全由Dart语言构建的SDK,它实现了一整套自底而上的基础库。 1.底部两层(Foundation和Animation、Painting、Gestures)是Flutter引擎暴露的底层UI库,提供动画、手势及绘制能力。 2.Rendering层是一个抽象的布局层,它依赖于dart UI层。Rendering层会构建一个UI树,当UI树有变化时,它会随即计算出有变化的部分,然后更新UI树,最终将UI树绘制到屏幕上。这个过程类似于React中的虚拟DOM。Rendering层可以说是Flutter UI框架最核心的部分,它除了确定每个UI元素的位置、大小之外,还要进行坐标变换和绘制(调用底层dart:ui)。 3.Widgets层是Flutter提供的一套基础组件库,在基础组件库之上,Flutter还提供了 Material 和Cupertino两种视觉风格的组件库。 Flutter Engine:这是一个完全由 C++实现的 SDK,其中包括了 Skia引擎、Dart运行时和文字排版引擎等。在代码调用 dart:ui库时,调用最终会走到Engine层,然后实现真正的绘制逻辑。 React Native、Weex和Flutter进行对比结果如下所示: 

六、总结

从Flutter的设计理念来看,其整体架构都是具有革命性的,相比于其他架构,它实现了真正意义上的跨平台。它能够让各平台的体验一致,并且让用户体验达到更优。现如今,Flutter的各种UI库和组件都在不断增加,与之相关的各种生态系统和社区也在不断完善,它对新的操作系统的适配性将会越来越强。相信在不久的将来,Flutter会慢慢成熟起来,成为主流的开发语言之一。

浅谈跨平台框架 Flutter 的优势与结构的更多相关文章

  1. 一文读懂跨平台框架 Flutter 的搭建与运行

    作者:个推iOS开发工程师 伊泽瑞尔 Flutter是Google推出的跨平台的解决方案,用以帮助开发者在 Android 和 iOS 两个平台开发高质量原生应用的全新移动 UI 框架. 之前我们为大 ...

  2. 手撸ORM浅谈ORM框架之基础篇

    好奇害死猫 一直觉得ORM框架好用.功能强大集众多优点于一身,当然ORM并非完美无缺,任何事物优缺点并存!我曾一度认为以为使用了ORM框架根本不需要关注Sql语句如何执行的,更不用关心优化的问题!!! ...

  3. 手撸ORM浅谈ORM框架之Add篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  4. 手撸ORM浅谈ORM框架之Update篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  5. 手撸ORM浅谈ORM框架之Delete篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  6. 手撸ORM浅谈ORM框架之Query篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  7. 【SSH学习笔记】浅谈SSH框架

    说在前面 本学期我们有一门课叫做Java EE,由陈老师所授,主要讲的就是Java EE 中的SSH框架. 由于陈老师授课风格以及自己的原因导致学了整整一学期不知道在讲什么,所以才有了自己重新学习总结 ...

  8. 浅谈Spring框架

    一.Spring简介 Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的.框架的主要优势之一就是其分层架构, 分层架构允许您选择使用哪一个组件,同时为 J2EE 应用程序开发提供集 ...

  9. 浅谈angular框架

    最近新接触了一个js框架angular,这个框架有着诸多特性,最为核心的是:MVVM.模块化.自动化双向数据绑定.语义化标签.依赖注入,以上这些全部都是属于angular特性,虽然说它的功能十分的强大 ...

随机推荐

  1. OFS环境,删除Resource 时出现错误失败,应该如何继续

    From the Windows failover cluster manager,select the group listener, stop it, and delete it.  Do the ...

  2. 汇编 MOV -2

    知识点:  MOV指令  基址  内联汇编  把OD附加到资源管理器右键菜单 一.MOV指令 aaa=0x889977;//MOV DWORD PTR DS:[0x403018],0x8899 ...

  3. [BZOJ4851][JSOI2016]位运算[矩阵快速幂]

    题意 给定长度为 \(\rm |S|\) 的 \(\rm 01\) 串并将其倍长 \(k\) 次得到一个 \(\rm|S|\times k\) 位的二进制数 \(R\) ,求有多少种在 \([0,R- ...

  4. 真机调试傻瓜图文教程(Xcode6.4)

    先准备好99刀,真机调试才带你玩. PS:万能宝十来块钱可以买个资格... Developer Apple上的设置 1.打开https://developer.apple.com/,点击Member ...

  5. 设计模式 笔记 生成器(建造者)模式 Builder

    //---------------------------15/04/08---------------------------- //builder 生成器(建造者)模式---对象创建型模式 /* ...

  6. Js_cookie保存登录名

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...

  7. Mistakes I Made(as a developer)...大龄程序员的忠告...(部分转...)

    在2006年,我开始了编程工作.当意识到来到了十年这个重要的时间关口时,我觉得有必要回顾一下这十年间所犯下的错误,做一做经验总结,并且给正在这个职业上奋斗的人们提出我的一些忠告.开发行业变化得很快,我 ...

  8. Java收发邮件过程中具体的功能是怎么实现的

    SMTP协议 用户连上邮件服务器后,要想给它发送一封电子邮件,需要遵循一定的通迅规则,SMTP协议就是用于定义这种通讯规则的. 因而,通常我们也把处理用户smtp请求(邮件发送请求)的邮件服务器称之为 ...

  9. mongodb lock 出毛病时解决方法

    错误信息: Error: couldn't connect to server 127.0.0.1:27017 at src/mongo/shell/mongo.js:145 解决办法: sudo r ...

  10. 1094. The Largest Generation (25)-(dfs,树的遍历,统计每层的节点数)

    题目很简单,就是统计一下每层的节点数,输出节点数最多的个数和对应的层数即可. #include <iostream> #include <cstdio> #include &l ...