跨平台开发的发展史

前言:flutter是什么?和react native,weex的异同?跨平台跨哪些平台?

现有平台技术简介:

平台 技术 实现
web平台 web开发 用html + css + javascript来构建一个PC端网页
移动设备平台 (Web APP)移动web开发 pc网页的缩小版加一些触摸特性,需要对网页进行响应式布局适应Mobile端
(Native APP)移动应用开发 (Android)界面布局:XML引用layout,界面控制:Java
(IOS)界面布局:mylayout/tangramkit,界面控制:oc/swift
(Hybrid APP)混合应用开发 用Native技术来搭建App的外壳,将一些页面抽出来用webview来实现,还可以使用phonegap将网页打包成app

跨平台开发的发展史

一、Native App 、Web App、Hybrid App纵向对比

首先,我们来看看什么是 Web App、Hybrid App、 Native App。

1. Native App

Native APP 基于智能手机本地操作系统如iOS、Android、WP并使用原生程式编写运行的第三方应用程序,一般开发的语言为Java、C++等。,有很强的交互是一个完整的App,可拓展性强。需要用户下载安装使用。

优点:

(1)打造完美的用户体验,用户留存率高
(2)性能稳定,操作速度快,上手流畅
(3)访问本地资源(通讯录,相册),可以调用移动硬件设备(摄像头、麦克风等)

缺点:

(1)开发成本高(每种移动操作系统都需要独立的开发项目,不同平台有不同的开发语言和界面适配)
(2)维护成本高(下载是用户控制的,例如一款App已更新至5.0版本,但仍有用户在使用3.0,2.0版本,需要更多的开发人员维护之前的版本)
(3)更新缓慢,应用商店发布审核周期长,安卓平台大概要1~3天,而iOS平台需要的时间更长

 

2. Web APP

跨平台开发的发展史

 

Web App基于web的系统和应用,运行于网络和浏览器之上,目前多采用h5标准开发,不需要下载安装。类似于现在所说的轻应用。生存在浏览器中的应用,基本上可以说是触屏版的网页应用。

优点。

(1)整体量级轻,开发成本低
(3)不需要安装包,节约手机空间,不需要手动更新升级,更便于业务的开展。
(4)基于浏览器,能够跨多个平台和终端。

缺点:

(1)临时性的入口,安全性相对较低,数据容易泄露或者被劫持
(2)页面跳转费力,不稳定感更强。在网速受到限制时,很多时候出现卡顿或者卡死现象,交互效果受到限制
(3)体验较差,用户留存率低

 

*不同的页面情况选择不同的开发方式

1.类似于短期活动和专题营销类的页面居多的,建议选择H5开发,便于活动的随时修改管理。参考京东首页采用的框架和各种随时变动的活动页。

2.对于业务流程类的核心功能页面,建议选择原生app开发,有更好的用户体验,使用上更为方便,而且拓展其他功能更方便。

3.如果讲究APP反应速度(含页面切换流畅性),则选用原生开发,因为H5其本质是网页,换页时,基本要加载整个页面,就像是浏览器打开一个新页面一样。

4.如果APP需要频繁调用硬件(摄像头、麦克风、未来的湿度检测仪等等)那么,基本选用原生开发,这样支持硬件更多,更 容易扩展,且调用速度更快。

5.预算有限,非H5不可~最直观体验,版本更新越来越少。

 

3. Hybrid App

Hybrid APP 中文名称是“混合app”,就是 native app 与 web app的混合。在native app里内置浏览器,合适的功能页面采用网页的形式呈现。比如京东的某些营销页面,今日头条的某些新闻页面、微信的腾讯新闻的内容页面等。集合了两种APP各自的优势。

  1. 在实现更多功能的前提下,使得App安装包不至于过大。
  2. 在应用内部打开Web网页,省去了跳转浏览器打开多个页面的麻烦。
  3. 主要功能区相对稳定下,增加的功能区采用Web形式,使得迭代更加方便。

跨平台开发的发展史

4.Web App、Hybrid App、Native App 技术特性

跨平台开发的发展史

 

二、最火移动端跨平台方案盘点:React Native、weex、Flutter

    为什么我们需要跨平台开发? 本质上,跨平台开发是为了增加代码复用,减少开发者对多个平台差异适配的工作量,降低开发成本,提高业务专注的同时,提供比web更好的体验。想要解决用户体验的问题,基本还是需要回到 native 来进行开发,但是这种行为必然会与平台绑定。其中一件事情就是自动将某个平台的代码转换到另外的平台上去。

 

目前移动端跨平台开发中,备受关注的方案大致归纳为以下几种情况:

1)react native、weex均使用JavaScript作为编程语言,目前JavaScript在跨平台开发中,占据半壁江山,大有“一统天下”的趋势;

2)flutter是Google跨平台移动UI框架,Dart作为谷歌的亲儿子,毫无疑问Dart成为flutter的编程语言。作为巨头新生儿,在flutter官网也可以看出,flutter同样“心怀天下”(可支持Web端、Android端、iOS端等)。

 

1、React Native的原理与特性介绍

技术关键词:Facebook 出品,JavaScript语言,JSCore引擎,React设计模式,原生渲染

       javascript目前仍是世界上最流行的语言,不管在web、服务端还是客户端都有广泛的应用,很多跨平台方案也采用js来实现,比如著名的reactjs,苹果在iOS7引入了javascriptcore库,提供更简单方便的方式将js接入,iOS7之前要执行js操作只能通过UIWebview中的。

      ReactJs和React Native的原理是相同的,都是由js实现的虚拟dom来驱动界面view层渲染。只不过ReactJs是驱动html dom渲染; React Native是驱动android/ios原生组件渲染

1.1 理念架构

“Learn once, write anywhere” ,代表着 Facebook对 react native 的定义:学习 react ,同时掌握 web 与 app 两种开发技能。 react native 用了 react 的设计模式,但UI渲染、动画效果、网络请求等均由原生端实现。开发者编写的js代码,通过 react native 的中间层转化为原生控件和操作,比ionic等跨平台应用,大大提高了的用户体验。

总结起来其实就是:React Native是利用 JS 来调用 Native 端的组件,从而实现相应的功能。

如下图所示,react native 的跨平台是实现主要由三层构成,其中 C++ 实现的动态连结库(.so),作为中间适配层桥接,实现了js端与原生端的双向通信交互。这里最主要是封装了 JavaScriptCore 执行js的解析,而 react native 运行在JavaScriptCore中,所以不存在浏览器兼容的问题。

跨平台开发的发展史

  • Java层:该层主要提供了Android的UI渲染器UIManager(将JavaScript映射成Android Widget)以及一些其他的功能组件等。
  • C++层:该层主要完成了Java与JavaScript的通信以及执行JavaScript代码两件工作。
  • JavaScript层:该层提供了各种供开发者使用的组件以及一些工具库。

1.2 实现原理

和前端开发不同:react native 所有的标签都不是真实控件,JS代码中所写控件的作用,类似 Map 中的 key 值。JS端通过这个 key 组合的 Dom ,最后Native端会解析这个 Dom ,得到对应的Native控件渲染,如 Android 中 标签对应 ViewGroup 控件。

可以看出,react native 跨平台的关键在于C++层,开发人员大部分时候,只专注于JS 端的代码实现。 在原生端提供的各种 Native Module 模块(如网络请求,ViewGroup控件),和 JS 端提供的各种 JS Module(如JS EventEmiter模块),都会在C++实现的so中保存起来,双方的通讯通过C++中的保存的映射,最终实现两端的交互。通信的数据和指令,在中间层会被转为String字符串传输。

1.3 打包加载

最终:JS代码会被打包成一个 bundle 文件,自动添加到 App 的资源目录下。react native 的打包脚本目录为/node_modules/react-native/local-cli,打包最后会通过 metro 模块压缩 bundle 文件。而bundle文件只会打包js代码,自然不会包含图片等静态资源,所以打包后的静态资源,其实是被拷贝到对应的平台资源文件夹中。

其中图片等存在资源的映射规则,比如放在 react native 项目根目录下的 img/pic/logo.png 的资源,编译时,会被重命名后,根据大小 merged 到对应的是drawable目录下,修改名称为img_pic_logo.png。

打包Android和IOS,肯定需要相应的平台项目存在,在 react-native init 时创建的项目,就已经包含了 android 和 ios 的模版工程,打包完的工程会加载bundle文件,然后启动项目。


 

2、WEEX的原理与特性介绍

技术关键词:阿里出品,JavaScript语言,JS V8引擎,Vue设计模式,原生渲染,尤雨溪

2.1 理念架构

“Write once, run everywhere”:weex的定义就像是:写个 vue 前端,顺便帮你编译成性能还不错的 apk 和 ipa。基于 Vue 设计模式,支持 web、android、ios 三端,原生端同样通过中间层转化,将控件和操作转化为原生逻辑来提高用户体验。

在 weex 中,主要包括三大部分:JS Bridge、Render、Dom,分别对应WXBridgeManager、WXRenderManager、WXDomManager,三部分通过WXSDKManager统一管理。其中 JS Bridge 和 Dom 都运行在独立的 HandlerThread 中,而 Render 运行在 UI 线程。

JS Bridge 主要用来和 JS 端实现进行双向通信,比如把 JS 端的 dom 结构传递给 Dom 线程。Dom 主要是用于负责 dom 的解析、映射、添加等等的操作,最后通知UI线程更新。而 Render 负责在UI线程中对 dom 实现渲染。

跨平台开发的发展史

2.2 实现原理

和 react native一样——weex 所有的标签也不是真实控件,JS 代码中所生成存的 dom,最后都是由 Native 端解析,再得到对应的Native控件渲染,如 Android 中 标签对应 WXTextView 控件。

weex 中文件默认为 .vue ,而 vue 文件是被无法直接运行的,所以 vue 会被编译成 .js 格式的文件,Weex SDK会负责加载渲染这个js文件。Weex可以做到跨三端的原理在于:在开发过程中,代码模式、编译过程、模板组件、数据绑定、生命周期等上层语法是一致的。不同的是在 JS Framework 层的最后,web 平台和 Native 平台,对 Virtual DOM 执行的解析方法是有区别的。

跨平台开发的发展史

2.3 实际上,在 Native 中对 bundle 文件的加载大致经历以下阶段:

1)weex 接收到 js 文件以后,JS Framework 根据文件为 Vue 模式,会调用weex-vue-framework 中提供的 createInstance方法创建实例。(也可能是Rax模式);

2)createInstance 中会执行 Js Entry 代码里 new Vue() 创建一个组件,通过其 render 函数创建出 Virtual DOM 节点;

3)由JS V8 引擎上解析 Virtual DOM ,得到 Json 数据发送至 Dom 线,这里输出 Json 也是方便跨端的数据传输;

4)Dom 线程解析 Json 数据,得到对应的 WxDomObject,然后创建对应的WxComponent 提交 Render;

5)Render在原生端最终处理处理渲染任务,并回调里JS方法。

得益于上层的统一性,只是通过 weex-vue-framework 判断是由Vue.js 生成真实的 Dom ,还是通过 Native Api 渲染组件,weex 一定程度上上,用JS 实现了vue 一统天下的效果。

跨平台开发的发展史

weex 在原生渲染 Render 时,在接收到渲染指令后,会逐步将数据渲染成原生组件。Render 通过解析渲染数据的描述,然后分发给不同的模块。

比如:控件渲染属于 dom 模块中,页面跳转属于navigator模块等。模块的渲染过程并非一个执行完,再执行另一个的流程,而是类似流式的过程。如上一个 的组件还没渲染好,下一个

的渲染又发了过来。这样当一个组件的嵌套组件很多时,或者可以看到这个大组件内的UI,一个一个渲染出来的过程。

weex 比起react native,主要是在JS V8的引擎上,多了 JS Framework 承当了重要的职责,使得上层具备统一性,可以支持跨三个平台。

总的来说JS Framework主要负责的是:

1)管理Weex的生命周期;

2)解析JS Bundle,转为Virtual DOM,再通过所在平台不同的API方法构建页面;

3)进行双向的数据交互和响应。

跨平台开发的发展史

3.4 打包

weex 作为 react-native 之后出现的跨平台实现方案,自然可以站在前人的肩膀上优化问题,比如:Bundle文件过大问题。

Bundle文件的大小,很大程度上影响了框架的性能,而 weex 选择将 JS Framework 集成到 WeexSDK 中,一定程度减少了JS Bundle的体积,使得 bundle 里面只保留业务代码。

打包时,weex 是通过 webpack 打包出 bundle 文件的。bundle 文件的打包和 entry.js 文件的配置数量有关,默认情况下之后一个 entry 文件,自然也就只有一个bundle文件。

在 weex 项目的 webpack.common.conf.js 中可以看到,其实打包也是区分了 webConfig 和 weexConfig 的不同打包方式。如下图,其中weexEntry 就是 weex 打包配置的地方,可以看到本来已经有 index 和 entry.js 存在了。

 

3、Flutter的原理与特性介绍

Flutter技术关键词:Google 出品,Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

Flutter 是谷歌2018年发布的跨平台移动UI框架。Flutter目前还是beta 阶段,这里更多的聊一下它的实现机制和效果。与 react native 和 weex 的通过 Javascript 开发不同,Flutter 的编程语言是Drat,所以执行时并不需要 Javascript 引擎,但实际效果最终也通过原生渲染。

  1. 热重载,利用Android Studio直接一个ctrl+s就可以保存并重载,模拟器立马就可以看见效果,就这一点比原生安卓制作快捷很多。
  2. 一切皆为Widget的理念,对于Flutter来说,手机应用里的所有东西都是Widget,通过可组合的空间集合、丰富的动画库以及分层课扩展的架构实现了富有感染力的灵活界面设计。
  3. 借助可移植的GPU加速的渲染引擎以及高性能本地代码运行时以达到跨平台设备的高质量用户体验。 最终结果就是利用Flutter构建的应用在运行效率上会和原生应用差不多。

 

3.1一切都是控件(Widget)

在Flutter中,每个应用程序都是Widget,这点和其他的应用框架不一样,Flutter的对象模型是统一的,也就是控件。
一个控件可以定义:

  • 结构元素(比如按钮或者菜单)
  • 风格元素(比如字体或者颜色方案)
  • 布局
  • 一些业务逻辑
    控件是基于构图形成层次结构,每个控件嵌套在其中,并从其父代继承属性,没有单独的“应用程序”对象,只有根控件。

您可以通过告知框架用另一个控件替换层次结构中的控件来响应事件,比如用户交互,然后框架会对比新的控件和旧的控件,并有效的更新用户界面,即更新有变化的控件。

也就是说,在Flutter中,一个应用就是有许许多多的Widget组合而成的。 

  • Text:文本控件,在应用中创建各种样式的文本。
    • Row,Column:Flex控件,可以创建水平(Row)或垂直(Column)方向的布局,是基于Web的flexbox的布局模式设计的。

Stack:非线性布局(水平或垂直),控件可以堆叠在其他控件上,可以使用Positioned控件控制Stack相对顶部、右部、底部和左部的位置,是基于Web的absolute定位的布局模式。

    • Container:创建矩形的可视元素,可以用BoxDecoration来设计样式,比如背景、边框和阴影,Container也有边距、填充和大小限制,另外,还可以在三维空间利用矩阵进行变换。
    • 跨平台开发的发展史

       

 

      Flutter 主要分为 Framework 和 Engine,我们基于Framework 开发App,运行在 Engine 上。Engine 是 Flutter 的独立虚拟机,由它适配和提供跨平台支持。得益于 Engine 层,Flutter 甚至不使用移动平台的原生控件, 而是使用自己 Engine 来绘制 Widget (Flutter的显示单元),而 Dart 代码都是通过 AOT 编译为平台的原生代码,所以 Flutter 可以 直接与平台通信,不需要JS引擎的桥接。同时 Flutter 唯一要求系统提供的是 canvas,以实现UI的绘制。在Flutter中,大多数东西都是widget,而widget是不可变的,仅支持一帧,并且在每一帧上不会直接更新,要更新而必须使用Widget的状态。无状态和有状态 widget 的核心特性是相同的,每一帧它们都会重新构建,有一个State对象,它可以跨帧存储状态数据并恢复它。

 

3.2 Dart之所以成为Flutter不可或缺的一部分,根本原因还是因为其具有以下特性:

1)Dart是AOT(静态)编译的,编译成快速、可预测的本地代码,使Flutter几乎都可以使用Dart编写。这不仅使Flutter变得更快,而且几乎所有的东西(包括所有的小部件)都可以定制;

2)Dart也可以JIT(动态)编译,开发周期异常快,工作流颠覆常规(包括Flutter流行的亚秒级有状态热重载);

3)Dart可以更轻松地创建以60fps运行的流畅动画和转场。Dart可以在没有锁的情况下进行对象分配和垃圾回收。就像JavaScript一样,Dart避免了抢占式调度和共享内存(因而也不需要锁)。由于Flutter应用程序被编译为本地代码,因此它们不需要在领域之间建立缓慢的桥梁(例如,JavaScript到本地代码)。它的启动速度也快得多;

4)Dart使Flutter不需要单独的声明式布局语言,如JSX或XML,或单独的可视化界面构建器,因为Dart的声明式编程布局易于阅读和可视化。所有的布局使用一种语言,聚集在一处,Flutter很容易提供高级工具,使布局更简单;

5)开发人员发现Dart特别容易学习,因为它具有静态和动态语言用户都熟悉的特性。

并非所有这些功能都是Dart独有的,但它们的组合却恰到好处,使Dart在实现Flutter方面独一无二。因此,没有Dart,很难想象Flutter像现在这样强大。

4、React Native、weex、Flutter 3种方案横向对比

跨平台开发的发展史

4.1 社群支持

react native 作为 Facebook 主力开源项目之一,至今已有各类丰富的第三方库,甚至如 realm、lottie 等开源项目也有 react native 相关的版本,社群实际无需质疑。当然,因为并完全正统开发平台,第三库的健壮性和兼容性有时候总是良莠不齐。

weex 其实有种生错在国内的感觉。其实 weex 的设计和理念都很优秀,性能也不错,但是对比 react native 的第三方支持,就显得有点后妈养的。2016年开源至今,社区和各类文档都显得有点疲弱,作为跨平台开发人员,大多时候肯定不会希望,需要频繁的自己增加原生功能支持,因为这样的工作一多,反而会与跨平台开发的理念背道而驰,带来开发成本被维护难度增加。

Flutter 目前还处理beta阶段,但是谷歌的号召力一直很可观,这一点无需质疑。

 

5. 最后:vue native悄悄崛起

 

nativescript的原理和react-native有点相似:提供一个运行环境,提供一个JavaScript引擎,android端是V8引擎,ios端是JavaScriptCore引擎,一个虚拟机上运行JavaScript代码,都可以调用平台api和ui组件。而nativescript更专注于创建一个与平台无关的单一的开发体验,react-native则是抽象业务逻辑的同时,支持每个平台UI呈现固有的差异,并把重心放在高性能的渲染和执行上面。