乐趣区

移动跨平台技术方案总结

“得移动端者得天下”,移动端取代 PC 端,成为了互联网行业最大的流量分发入口,因此不少公司制定了“移动优先”的发展策略。
为了帮助读者更好地学习 WEEX,本节将对 React Native、Weex 和 Flutter 等主流的跨平台方案进行简单的介绍和对比。
React Native
React Native (简称 RN) 是 Facebook 于 2015 年 4 月开源的跨平台移动应用开发框架,是 Facebook 早先开源的 React 框架在原生移动应用平台的衍生产物,目前主要支持 iOS 和安卓两大平台。
RN 使用 Javascript 语言来开发移动应用,但 UI 渲染、网络请求等均由原生端实现。具体来说,开发者编写的 Javascript 代码,通过中间层转化为原生控件后再执行,因此熟悉 Web 前端开发的技术人员只需很少的学习就可以进入移动应用开发领域,并可以在不牺牲用户体验的前提下提高开发效率。
作为一个跨平台技术框架,RN 从上到下可以分为 Javascript 层、C++ 层和 Native 层。其中,C++ 层主要用于实现动态连结库 (.so),作为中间适配层桥接,实现 js 端与原生端的双向通信交互,如下图所示是 RN 在 Android 平台上的通信原理图。
在 RN 的三层架构中,最核心的就是中间的 C ++ 层,C++ 层最核心的功能就是封装 JavaScriptCore,用于执行对 js 的解析。同时,原生端提供的各种 Native Module(如网络请求,ViewGroup 控件模块)和 JS 端提供的各种 JS Module(如 JS EventEmiter 模块)都会在 C ++ 实现的 so 文件中保存起来,最终通过 C ++ 层中的保存的映射实现两端的交互。
在 RN 开发过程中,大多数情况下开发人员并不需要需要了解 RN 框架的具体细节,只需要专注 JS 端的逻辑代码实现即可。但是需要注意的是,由于 js 代码是运行在独立的 JS 线程中,所以在 js 中不能处理耗时的操作,如 fetch、图片加载和数据持久化等操作。
最终,JS 代码会被打包成一个 bundle 文件并自动添加到应用程序的资源目录下,而应用程序最终加载的也是打包后的 bundle 文件。RN 的打包脚本位于“/node_modules/react-native/local-cli”目录下,打包后通过 metro 模块压缩成 bundle 文件,而 bundle 文件只包含打包 js 的代码,并不包含图片、多媒体等静态资源,而打包后的静态资源会是被拷贝到对应的平台资源文件夹中。
总的来说,RN 使用 Javascript 来编写应用程序,然后调用原生组件执行页面渲染操作,在提高了开发效率的同时又保留了 Native 的用户体验。并且,伴随着 Facebook 重构 RN 工作的完成,RN 也将变得更快、更轻量、性能更好。
Weex
作为一套前端跨平台技术框架,Weex 建立了一套源码转换以及 Native 与 Js 通信的机制。Weex 表面上是一个客户端框架,但实际上它串联起了从本地开发、云端部署到分发的整个链路。具体来说,在开发阶段编写一个.we 文件,然后使用 Weex 提供的 weex-toolkit 转换工具将.we 文件转换为 JS bundle,并将生成的 JS bundle 上传部署到云端,最后通过网络请求或预下发的方式加载至用户的移动应用客户端。当集成了 Weex SDK 的客户端接收到 JS bundle 文件后,调用本地的 JavaScript 引擎执行环境执行相应的 JS bundle,并将执行过程中产生的各种命令发送到 native 端进行界面渲染、数据存储、网络通信以及用户交互响应。由上图可知,Weex 框架中最核心的部分就是 JavaScript Runtime。具体来说,当需要执行渲染操作时,在 iOS 环境下选择基于 JavaScriptCore 内核的 iOS 系统提供的 JSContext,在 Android 环境下使用基于 JavaScriptCore 内核的 JavaScript 引擎。
当 JS bundle 从服务器下载完成之后,Weex 的 Android、iOS 和 H5 会运行一个 JavaScript 引擎来执行 JS bundle,同时向各终端的渲染层发送渲染指令,并调度客户端的渲染引擎实现视图渲染、事件绑定和处理用户交互等操作。由于 Android、iOS 和 H5 等终端最终使用的是 native 渲染引擎,也就是说使用同一套代码在不同终端上展示的样式是相同的,并且 Weex 使用 native 引擎渲染的是 native 组件,所以在性能上比传统的 WebView 方案要好很多。
当然,尽管 Weex 已经提供了开发者所需要的最常用的组件和模块,但面对丰富多样的移动应用研发需求,这些常用基础组件还是远远不能满足开发的需要,因此 Weex 提供了灵活自由的扩展能力,开发者可以根据自身的情况定制属于自己客户端的组件和模块,从而丰富 Weex 生态。
Flutter
Flutter 是 Google 开源的移动跨平台框架,其历史最早可以追溯到 2015 年的 Sky 项目,该项目可以同时运行在 Android、iOS 和 fuchsia 等包含 Dart 虚拟机的平台上,并且性能无限接近原生。相较于 RN 和 Weex 使用 Javascript 作为编程语言与使用平台自身引擎渲染界面不同,Flutter 直接选择 2D 绘图引擎库 skia 来渲染界面。
如上图所示,Flutter 框架主要由 Framework 和 Engine 层组成,而我们基于 Framework 开发 App 最终会运行在 Engine 上。其中,Engine 是 Flutter 提供的独立虚拟机,正是由于它的存在 Flutter 程序才能运行在不同的平台上,实现跨平台运行的能力。与 RN 和 Weex 使用原生控件渲染界面不同,Flutter 并不需要使用原生控件来渲染界面,而是使用 Engine 来绘制 Widget(Flutter 显示单元),并且 Dart 代码会通过 AOT 编译为平台的原生代码,实现与平台的直接通信,不需要 JS 引擎的桥接,也不需要原生平台的 Dalvik 虚拟机,如图 1 - 5 所示。同时,Flutter 的 Widget 采用现代响应式框架来构建,而 Widget 是不可变的,仅支持一帧,并且每一帧上的内容不能直接更新,需要通过 Widget 的状态来间接更新。在 Flutter 中,无状态和有状态 Widget 的核心特性是相同的,视图的每一帧 Flutter 都会重新构建,通过 State 对象 Flutter 就可以跨帧存储状态数据并恢复它。
总的来说,Flutter 是目前跨平台开发中最好的方案,它以一套代码即可生成 Android 和 iOS 平台两种应用,很大程度上减少了 App 开发和维护的成本,同时 Dart 语言强大的性能表现和丰富的特性,也使得跨平台开发变得更加便利。而不足的是,Flutter 还处于 Alpha 阶段,许多功能还不是特别完善,而全新的 Dart 语言也带来了学习上的成本,如果想要完全替代 Android 和 iOS 开发还有比较长的路要走。
PWA
PWA,全称 Progressive Web App,是 Google 在 2015 年提出渐进式的网页技术。PWA 结合了一系列的现代 Web 技术,并使用多种技术来增强 Web App 的功能,最终可以让网页应用呈现和原生应用相似的体验。
相比于传统的网页技术,渐进式 Web 技术是可以横跨 Web 技术及 Native APP 开发的技术解决方案,具有可靠、快速且可参与等诸多特点。
具体来说,当用户从手机主屏幕启动时,不用考虑网络的状态就可以立刻加载出 PWA。并且,相比传统的网页加载速度,PWA 的加载速度是非常快的,因为 PWA 使用了 Service Worker 等先进技术。除此之外,PWA 还可以被添加在用户的主屏幕上,不用从应用商店进行下载即可通过网络应用程序 Manifest file 提供类似于 APP 的使用体验。
作为一种全新 Web 技术方案,PWA 的正常工作需要一些重要的技术组件,它们协同工作并为传统的 Web 应用程序注入活力,如图 1 - 8 所示。
其中,Service Worker 表示离线缓存文件,其本质是 Web 应用程序与浏览器之间的代理服务器,可以在网络可用时作为浏览器和网络间的代理,也可以在离线或者网络极差的环境下使用离线的缓冲文件。
Manifest 则是 W3C 一个技术规范,它定义了基于 JSON 的清单,为开发人员提供一个放置与 Web 应用程序关联的元数据的集中地点。Manifest 是 PWA 开发中的重要一环,它为开发人员控制应用程序提供了可能。
目前,渐进式 Web 应用还处于起步阶段,使用的厂商也是诸如 Twitter、淘宝、微博等大平台。不过,PWA 作为 Google 主推的一项技术标准,Edge、Safari 和 FireFox 等主流浏览器也都开始支持渐进式 Web 应用。因此,可以预见的是,PWA 必将成为继移动之后的又一革命性技术方案。
对比
在当前诸多的跨平台方案中,RN、Weex 和 Flutter 无疑是最优秀的。而从不同的细节来看,三大跨平台框架又有各自的优点和缺点,可以通过表 1 - 1 来查看。

对比类型
React Native
Weex
Flutter

支持平台
Android/IOS
Android/IOS/Web
Android/IOS

实现技术
JavaScript
JavaScript
原生编码 / 渲染

引擎
JS V8
JSCore
Flutter Engine

编程语言
React
Vue
Dart

bundle 包大小
单一、较大
较小、多页面
不需要

框架程度
较重
较轻

社区
活跃、FB 维护
不活跃
活跃

如上表所示,RN、Weex 采用的技术方案大体相同,它们都使用 JavaScript 作为编程语言,然后通过中间层转换为原生的组件后再利用 Native 渲染引擎执行渲染操作。而 Flutter 直接使用 skia 来渲染视图,而 Flutter Widget 则使用现代响应式框架来构建,和平台没有直接的关系。就目前跨平台技术来看,JavaScript 在跨平台开发中可谓占据半壁江山,大有“一统天下”的趋势。从性能方面来说,Flutter 的性能理论上是最好的,RN 和 Weex 次之,并且都好于传统的 WebView 方案。但从目前的实际应用来看却并没有太大的差距,特别是和 0.5.0 版本以上的 RN 对比性能体验上差异并不明显。而从社群和社区的活跃来看,RN 和 Flutter 无疑是最活跃的,RN 经过 4 年多的发展已经成长为跨平台开发的实际领导者,并拥有各类丰富的第三方库和开发群体。Flutter 作为最近才火起来的跨平台技术方案,不过目前还处在 beta 阶段,商用的实例也很少,不过应该看到 google 的号召力一直是很强,未来究竟如何发展让我们拭目以待。
示例
eros-yanxuan
简介
eros-yanxuan 是基于 eros 开发的 Weex 项目,部分页面参考了项目网易严选 weex 版本,欢迎 star 或 fork。

eros 文档
eros github

运行
确保你本地已经集成了 eros 开发所需的环境。
clone 项目到本地:
$ git clone https://github.com/xiangzhihong/eros-yanxuan.git
进入目录,下载前端所需的依赖:
$ cd eros-yanxuan
$ npm install
iOS SDK
打开 platforms 目录下的 WeexEros 项目,在 WeexEros 中使用 pod 添加依赖。
$ cd platforms/ios/WeexEros
$ pod update // 下载 iOS 依赖
$ open WeexEros.xcworkspace // 自动打开项目
选中模拟器,点击绿色箭头运行 app 即可。
Android
对于 Android 工程来说,使用 Android Studio 打开 platforms 目录下的 WeexFrameworkWrapper 的 Android 工程,然后使用 install.sh 安装 Android 工程的需要依赖包 nexus 和 wxframework。
具体可以参考自行导入项目,便可运行起来。
运行

项目根目录下运行 eros dev

关闭调试,拦截器,打开热更新
重新 build app

效果

Question
运行过程中出现问题在以下地址解决方法,如果没有找到,请加群:515980159

eros issue
eros Q&A

退出移动版