移动跨平台开发深度解析

注:本文为转载文章,部份内容参考移动端跨平台开发的深度解析,并作了精简和加工。前端

概述

移动跨平台开发一直是移动开发者和前端开发者追求的的话题,从早期的cordova、ionic,到现在的react native、weex、kotlin native和flutter等,能够说现在的跨平台框架可谓百花齐放,很有一股推倒原生开发者的势头。vue

若是要对目前的跨平台的方案进行一个总结,大体能够分为如下几个流派: JavaScript流派:这一流派中,最明显的特征是使用JavaScript做为编程语言,react native、weex均属于这一流派。和其余跨平台方案相比,JavaScript在跨平台开发中,使用者最多,大有“一统天下”的趋势。 VM虚拟机:与其余方案不一样,kotlin提供的kotlin-native技术拥有本身的VM,能够同时支持Android、iOS 和 Web 开发。 Flutter:Futter是Google开源的移动跨平台UI框架,使用的是Google本身的Dart编程语言,因为是Google推出的产品,于是也受到不少开发者的喜好。node

不过,综合对比开发现,目前最火的跨平台开发方案,特别是已经商用的跨平台开发框架中,react native无疑是老大,其次是Weex(毕竟是阿里的产品),最后多是最近才火起来的Flutter。react

React Native

曾经,React Native的口号是“Learn once, write anywhere”,这句话表明了FaceBook对React Native设计的初衷:学习 react ,同时掌握 web 与 app 两种开发技能。android

借助FaceBook旗下的React的设计模式 , React Native使用的UI渲染、动画效果、网络请求等会转换成原生端的实现。也就是说,开发者编写的js代码,经过 react native 的中间层(JavaScriptCore)转化为原生控件和操做,这就最大程度的接近原生应用的用户体验,并提升了开发的效率。webpack

React Native的结构

React Native的跨平台是实现主要由三层构成,其中 C++ 实现的动态连结库(.so),做为中间适配层桥接,实现了js端与原生端的双向通讯交互。ios

这里最主要是封装了 JavaScriptCore 执行js的解析,而 react native 运行在JavaScriptCore中,因此不存在浏览器兼容的问题。其结构如以下图:web

原理

React Native实现的原理其实就是利用JS 调用Native 端的组件,并使用Native的组件来绘制界面,从而达到媲美原生应用的效果。apache

和前端开发不一样,React Native 所使用的标签并非真实的控件,React Native提供的组件会Dom 转换为Native的控件进行渲染。例如<Text> 标签会被转换为Android 中对应 TextView 控件。编程

须要说明的是,在React Native 中,JS端是运行在独立的线程中(称为JS Thread ),JS Thread 做为单线程逻辑,不可能处理耗时的操做。那么如 fetch 、图片加载 、 数据持久化等操做,在 Android 中实际对应的是 okhttp 、Fresco 、SharedPreferences等。而跨线程通讯,也意味着 Js Thread 和原生之间交互与通信是异步的。

由此能够看出,跨平台的关键在于C++层,开发人员大部分时候,只专一于JS 端的代码实现便可,无线了解底层的实现细节。 而若是要实现和原生模块的交互,只须要在原生端提供的各类 Native Module 模块(如网络请求,ViewGroup控件)便可,而后经过 JS 端提供的各类 JS Module(如JS EventEmiter模块)来实现调用。而且这些调用都会在C++实现的so中保存起来,双方的通信经过C++中的保存的映射,最终实现两端的交互,通讯的数据和指令,在中间层会被转为String字符串传输,双向的调用流程以下图。

打包与发布

在React Native混合项目中,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。

Weex

Weex是阿里巴巴开源的一套移动跨平台开发框架,可以完美兼顾性能与动态性,让移动开发者经过简捷的前端语法写出Native级别的性能体验,并支持iOS、安卓、YunOS及Web等多端部署。目前,使用Weex框架的多半是阿里系的产品和一些创业的公司。

Weex架构

Weex的口号是“Write once, run everywhere”,Weex使用的耳熟能详的Vue,阿里的思惟是:写个 vue 前端,顺便完成一个apk 和 ipa,但其实仍是有差距的。Weex支持 web、android、ios 三端,原生端一样经过中间层转化,将控件和操做转化为原生逻辑来提升用户体验。。

在 Weex的架构层次中,主要包括三大部分:JS Bridge、Render、Dom,分别对应WXBridgeManager、WXRenderManager、WXDomManager,三部分经过WXSDKManager统一管理。其中 JS Bridge 和 Dom 都运行在独立的 HandlerThread 中,而 Render 运行在 UI 线程。关于Weex架构分层的内容读者能够自行查看官方资料的介绍。

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

实现原理

和 React Native同样,Weex 全部的标签也不是真实控件,Weex的标签只不过是JS 代码中所生成存的 dom,最后都是由 Native 端解析,再获得对应的Native控件渲染。如 Android 中 <text> 标签对应 WXTextView 控件。

Weex 中文件默认为 .vue ,而 vue 文件是被没法直接运行的,因此 vue 会被编译成 .js 格式的文件,Weex SDK会负责加载渲染这个js文件。Weex能够作到跨三端的原理在于:在开发过程当中,代码模式、编译过程、模板组件、数据绑定、生命周期等上层语法是一致的。

不一样的是,在 JS Framework 层的最后,web 平台和 Native 平台,对 Virtual DOM 执行的解析方法是有区别的,在渲染真实 UI 的时候调用的接口也不一样的。

Weex 表面上是一个客户端技术,但实际上它串联起了从本地开发、云端部署到分发的整个链路。开发者首先可在本地像编写 web 页面同样编写一个 app 的界面,而后经过命令行工具将之编译成一段 JavaScript 代码,生成一个 Weex 的 JS bundle;同时,开发者能够将生成的 JS bundle 部署至云端,而后经过网络请求或预下发的方式加载至用户的移动应用客户端;在移动应用客户端里,Weex SDK 会准备好一个 JavaScript 执行环境,而且在用户打开一个 Weex 页面时在这个执行环境中执行相应的 JS bundle,并将执行过程当中产生的各类命令发送到 native 端进行界面渲染、数据存储、网络通讯、调用设备功能及用户交互响应等功能;同时,若是用户但愿使用浏览器访问这个界面,那么他能够在浏览器里打开一个相同的 web 页面,这个页面和移动应用使用相同的页面源代码,但被编译成适合Web展现的JS Bundle,经过浏览器里的 JavaScript 引擎及 Weex SDK 运行起来的。

其中, Native 加载bundle 文件大体经历了如下阶段:

  • weex 接收到 js 文件之后,JS Framework 根据文件为 Vue 模式,会调用weex-vue-framework 中提供的createInstance方法建立实例。
  • createInstance 中会执行 Js Entry 代码里 new Vue() 建立一个组件,经过其 render 函数建立出 Virtual DOM 节点。
  • 由JS V8 引擎上解析 Virtual DOM ,获得 Json 数据发送至 Dom 线,这里输出 Json 也是方便跨端的数据传输。
  • Dom 线程解析 Json 数据,获得对应的 WxDomObject,而后建立对应的WxComponent 提交 Render 。
  • Render在原生端最终处理处理渲染任务,并回调里JS方法。

相比React Native,Weex主要是在JS V8的引擎上多了 JS Framework 承当了重要的职责,使得上层具有统一性,能够支持跨三个平台。总的来讲它主要负责是:管理Weex的生命周期,解析JS Bundle,转为Virtual DOM,再经过所在平台不一样的API方法,构建页面;进行双向的数据交互和响应。

打包与发布

在打包方案上,Weex和React Native都经过 Webpack 来打包bundle 文件的。不过,React Native打包若是不作拆分,打出的包是很大的,于是会本身制定一些拆包的规则。而Weex 做为React Native以后出现的跨平台实现方案,天然能够站在前人的肩膀上优化问题,好比:Bundle文件过大问题。 Weex 选择使用JS Framework 集成到 WeexSDK的方式,必定程度减小了JS Bundle的体积,使得 bundle 里面只保留业务代码。

打包时,weex 是经过 webpack 打包出 bundle 文件的。bundle 文件的打包和 entry.js 文件的配置数量有关,默认状况下以后一个 entry 文件,天然也就只有一个bundle文件。   在 weex 项目的 webpack.common.conf.js 中能够看到,其实打包也是区分了 webConfig 和 weexConfig 的不一样打包方式。

Flutter

Flutter是Google用以帮助开发者在Ios和Android两个平台开发高质量原生应用的全新移动UI框架。与 React Native 和 Weex 框架使用的Javascript 技术不一样,Flutter 使用的是全新的编程语言Drat,因此执行时并不须要 Javascript 引擎,但实际效果最终也经过原生渲染。

Flutter框架

Flutter框架主要分为 Framework 和 Engine两层,咱们基于Framework 开发App主要运行在 Engine 上。Engine 是 Flutter 的独立虚拟机,由它适配和提供跨平台支持,目前猜想 Flutter 应用程序在 Android 上,是直接运行 Engine 上 因此在是不须要Dalvik虚拟机。其架构图以下图所示:

得益于 Engine 层,Flutter 甚至不使用移动平台的原生控件, 而是使用本身 Engine 来绘制 Widget (Flutter的显示单元),而 Dart 代码都是经过 AOT 编译为平台的原生代码,因此 Flutter 能够 直接与平台通讯,不须要JS引擎的桥接。

而Flutter惟一要求系统提供的是canvas,用以实现UI的绘制。不过,Flutter 上 Android 自带了 Skia,Skia是一个 2D的绘图引擎库,跨平台,因此能够被嵌入到 Flutter的 iOS SDK中,也使得 Flutter Android SDK要比 iOS SDK小不少。

对比

下面对上面介绍的几大框架进行一个简单的对比,以方便读者进行对比学习。

对比类型 React Native Weex Flutter
实现技术 JavaScript JavaScript 原生编码,无桥接
引擎 JS V8 JSCore Flutter engine
使用语言 React Vue Dart
bundle文件大小 默认单1、较大 较小、多页面可多文件 不须要
上手难度 稍高大 容易 简单
框架难度 较重 较轻
支持对象 Android、IOS Android、IOS、Web Android、IOS

包大小对比

上面Apk大小是经过 react-native init、weex create 和 flutter 建立出的工程后,直接不添加任何代码,打包出来的 release 签名 apk 大小。从下图能够看出,其中大比例都是在so库。

附: React Native中文网 Weex官方文档 Flutter中文社区

相关文章
相关标签/搜索