移动跨平台方案总结

举报
竹叶青 发表于 2019/10/15 21:02:27 2019/10/15
【摘要】 概述移动跨平台开发一直是移动开发者和前端开发者追求的的话题,从早期的cordova、ionic,到如今的react native、weex、kotlin native和flutter等,可以说如今的跨平台框架可谓百花齐放,颇有一股推倒原生开发者的势头。如果要对目前的跨平台的方案进行一个总结,大致可以分为以下几个流派: JavaScript流派:这一流派中,最明显的特征是使用JavaScrip...

top4.5c784cf.png

概述

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

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

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


1534058703018044113.png

React Native

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

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

React Native的结构

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

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

原理

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

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

需要说明的是,在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字符串传输,双向的调用流程如下图。 
4.png

打包与发布

在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 实现渲染。 
5.png

实现原理

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


7.png

其中, 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虚拟机。其架构图如下图所示: 
8.png

得益于 Engine 层,Flutter 甚至不使用移动平台的原生控件, 而是使用自己 Engine 来绘制 Widget (Flutter的显示单元),而 Dart 代码都是通过 AOT 编译为平台的原生代码,所以 Flutter 可以 直接与平台通信,不需要JS引擎的桥接。 
9.png

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

对比

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

对比类型React NativeWeexFlutter
实现技术JavaScriptJavaScript原生编码,无桥接
引擎JS V8JSCoreFlutter engine
使用语言ReactVueDart
bundle文件大小默认单一、较大较小、多页面可多文件不需要
上手难度稍高大容易简单
框架难度较重较轻
支持对象Android、IOSAndroid、IOS、WebAndroid、IOS

包大小对比

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

本文转载自异步社区

原文链接:

https://www.epubit.com/articleDetails?id=Ne91f7f10-84c9-4c19-b6f7-04c6d4d63355


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。