目前情况

自从移动系统安卓和 iOS 流行起来之后,各大企业在 PC 端,web 网页之外,又多了两个需要支持的平台,开发一项新功能,需要考虑不同的平台特性,以及开发成本。每个平台的架构不同,设计规范不同,最终做出的效果也有差异。基于这些情况,跨端技术逐渐成为各大企业技术关注的方向。
跨端的本质需求是降本增效,简单来说就是追求性价比,在开发成本和产品体验之间取得最优解。目标是一份代码,能够运行在多个平台,并且保持多端体验统一。想象的很美好,但是目前现实是没有一套整合的方案,每个厂商都需要推广自己的平台,建立自己的护城河,无法推动一套统一的技术标准,做为开发者,我们需要根据项目的情况选择合适的技术,这个主题主要谈谈跨端技术。
目前业内主流的应用开发技术方案大致分为以下五种:
  • 以 Web 为基础的 H5 Hybrid 方案原生的 WebView 作为容器,内部用网页显示,底层使用 WebKit 渲染引擎,通过JavaScript Bridge 来和原生通信。
  • 以微信小程序为代表的小程序方案,由宿主应用提供的开发框架进行开发,底层实现由宿主应用控制,WebView进行渲染。
  • 将 JavaScriptCore 引擎当作虚拟机的方案,代表框架是 React Native,Weex。
  • 使用非 JavaScriptCore 虚拟机的方案,代表框架是 Flutter。
  • 原生框架实现,如 UIKit。

方案比较

接下来我分别对这几种方案特点做一下分析:

Hybrid

这种方案简单来说是展示一个H5页面,利用网页可以在各个平台访问来实现跨端的效果,现在几乎所有的平台都支持 webview,如果受制于成本和时间,想要最快的一份代码支持所有平台和设备,无疑 web 前端是目前最好的选择,在移动设备上使用 WebView 为载体,在桌面端可以使用 Electron 打包成应用。
Hybrid 方案基于Chromium/WebKit引擎,网页和原生的交互通过 JSB(JavaScript Bridge) 来实现。在 iOS 上,如果要调用原生的方法,iOS 9 之前使用 UIWebView 通过 JavaScriptCore 引擎来通信,之后使用 WKWebView 来做为容器。WebKit 的渲染层来自以前 macOS 的 Layer Rendering 架构,而 iOS 也是基于这一套架构。所以,从本质上来看,WebKit 和 iOS 原生渲染差别不大。
但是从内容加载以及代码执行性能上来说,WebView 就有很多不足,WebView 需要额外加载和解析 HTML + CSS + JavaScript 代码,并且 WebView 在初次启动的时候会初始化一些全局服务和资源,这就导致了加载速度较慢,如果网络条件不佳的情况下会更加明显,不过可以通过本地缓存等方式进行一些优化,从语言本身的解释执行性能来看,大前端加载后的界面更新会通过 JavaScript 解释执行,而 JavaScript 解释执行性能要比原生差,特别是解释执行复杂逻辑或大量计算时。所以,前端的运算速度,要比原生慢不少。除此以外,WebView 的渲染进程是单独的,每帧的更新都要通过 IPC 调用 GPU 进程。频繁的 IPC 进程通信也会有性能损耗。
优点
  • 动态更新能力强,不需要版本审核,随时更新。
  • 跨平台,不同平台体验基本一致,标准统一,兼容性好。
  • 开发成本低。
  • 社区生态繁荣。
缺点
  • 由于底层的原因,加载和执行效能较差,导致 web 的体验相对原生要差。
  • 内存占用高,不适合做游戏,音视频等类型的应用。
  • 对于很多系统级的权限,无法直接获取,需要借助 JSBridge 通过原生实现。
  • 本地数据存储能力有限,不适合中大型项目。
  • 如果想要达到近原生应用的效果,依然需要掌握 Native 相关能力。
 
总的来说,Hybrid 方案如果想要做到很好的效果,依然离不开 Native 的开发,并且很大程度上依赖 JavaScript Bridge 中间层来进行交互,这样的机制劣势也很明显,就是前端页面与原生系统的通信完全取决于JSB的构造,如果JSB中缺少调用原生能力的接口,那跨段能力也会直接受限。这种情况下依旧需要分别扩充原生应用中的JSB接口,反而降低了开发效率,并且还有一个问题是 Apple 对这种方式不推荐,使用这种方式提交审核将会面临较大的被拒风险。综上因素,目前全局使用Hybrid 方案的应用较少,大部分是部分业务和界面使用 webview 展示,例如微信文章页,资讯类 App内容页等。
 
相关文档
 

小程序

小程序最先由微信于 2017 年 1 月 9 日推出,随后其他各大厂也随即跟进,现在我们说的小程序主要指微信小程序。小程序可以认为是内嵌在宿主应用中的轻量级 ”app”,它主要有四大特性:无需安装,触手可及,用完即走,无需卸载,因为对其大小进行了限制,所以下载安装速度非常快,给用户一种不需要安装的感觉。小程序采用的都是 AppService 和 WebView 的双线程模型,基于 WebView 和原生控件混合渲染的方式,小程序优化扩展了 Web 的基础能力,保证了在移动端上有良好的性能和用户体验。
小程序的渲染层和逻辑层分别由两个线程管理: 1. 渲染层的界面使用 WebView 进行渲染; 2. 逻辑层采用 JSCore 或者 V8 等JS引擎 来运行 JavaScript 代码。 一个小程序存在多个界面,所以渲染层存在多个 WebView。这两个线程间的通信经由小程序 Native 侧中转,逻辑层发送网络请求也经由 Native 侧转发,小程序的通信模型下图所示。
notion image
优点
  • 跨平台,使用便捷。
  • 开发门槛低,周期短,成本低。
  • 体验相比网页而言更好,更接近原生体验。
  • 借助宿主提供便利的 API 和开发框架,调用原生能力更优秀,性能也更好。
  • 基于微信的生态,能够减少用户使用的门槛。
缺点
  • 包大小有限制,无法承载复杂业务。
  • 因为逻辑层运行在JSCore中,缺少DOM 和 BOM API。
  • 收到宿主应用的限制较多,功能丰富度和开放性不如 App,并且发布也需要审核。
  • 无法主动触及用户,必须由用户主动打开。
  • 入口层级深,曝光率较低。
 
小程序的优缺点很明显,是介于纯 WebView 和 Native 之间的一种选择,性能体验优于WebView,在WebView的基础上做了诸多优化和改进,同时借助于微信生态,用户使用几乎没有任何成本,但是缺点也很明显,也正是基于微信,导致他注定只能够用来实现轻量级的业务,并且依靠平台就要受限于平台,有得必有失,对于初创团队,如果想要快速试错并得到市场反馈,小程序是一个不错的选择,兼顾了体验和成本。
 
相关文档
微信小程序原理分析和多端小程序架构原理(应该是全网最全了)
互联网生态演进:超级 APP + 小程序成为「轻应用时代」下的新生态。 一方面微信、支付宝等各家小程序平台遍地开花,另一方面移动开发插件化技术逐渐没落,移动应用构建的方式在悄悄的发生变化。对于企业应用形态而言,也在逐步发生变化,超级 APP(移动门户)+ 轻应用是一种新的流行趋势。微信、支付宝是互联网生态下的"移动门户",手机银行是金融典型的 ToC "移动门户"。小程序方式构建应用是大趋势,被越来越多的企业用户看到其中的优势,构建一个跨多端平台的小程序开发平台是一种思路,帮助企业用户构建一个具备小程序能力的"移动门户"也是一种思路。本文主要调研微信小程序运行时的基本原理,从而构建一个适合我们自己平台的小程序运行框架。 小程序的渲染层和逻辑层分别由两个线程管理:(1) 渲染层的界面使用 WebView 进行渲染;(2) 逻辑层采用 JSCore 或者 V8 等JS引擎 来运行 JavaScript 代码。一个小程序存在多个界面,所以渲染层存在多个 WebView。这两个线程间的通信经由小程序 Native 侧中转,逻辑层发送网络请求也经由 Native 侧转发,小程序的通信模型下图所示。 类似于微信 JSSDK 这样的 Hybrid 技术,微信小程序的界面主要由成熟的 Web 技术渲染,辅之以大量的接口提供丰富的客户端原生能力。同时,每个小程序页面都是用不同的 WebView 去渲染,这样可以提供更好的交互体验,更贴近原生体验,也避免了单个 WebView 的任务过于繁重。此外,界面渲染这一块我们定义了一套内置组件以统一体验,并且提供一些基础和通用的能力,进一步降低开发者的学习门槛。值得一提的是,内置组件有一部分较复杂组件是用客户端原生实现的同层渲染,以提供更好的性能。 为了管控和安全,微信小程序阻止开发者使用一些浏览器提供的,诸如跳转页面、操作 DOM、动态执行脚本的开放性接口。将逻辑层与视图层进行分离,视图层和逻辑层之间只有数据的通信,可以防止开发者随意操作界面,更好的保证了用户数据安全。 总的来说,跟浏览器的线程模型相比,小程序的双线程模型解决了或者说规避了Web Worker堪忧的性能,同时又实现了与Web Worker相同的线程安全,从性能和安全两个角度实现了提升。可以概括地说,双线程模式是受限于浏览器现有的进程和线程管理模式之下,在小程序这一具体场景之内的一种改进的架构方案。 微信小程序视图层是 WebView,逻辑层是 JS 引擎。三端的脚本执行环境以及用于渲染非原生组件的环境是各不相同的: 单 WebView 模式下,Page 视图与
微信小程序原理分析和多端小程序架构原理(应该是全网最全了)
lionvoom/WeAppTongCeng
小程序同层渲染原理剖析
众所周知,小程序当中有一类特殊的内置组件--原生组件,这类组件有别于 WebView 渲染的内置组件,他们是交由原生客户端渲染的。原生组件作为 Webview 的补充,为小程序带来了更丰富的特性和更高的性能,但同时由于脱离 Webview 渲染也给开发者带来了不小的困扰。在小程序引入「同层渲染」之前,原生组件的层级总是最高,不受 z-index 属性的控制,无法与 view、 image 等内置组件相互覆盖, cover-view 和 cover-image 组件的出现一定程度上缓解了覆盖的问题,同时为了让原生组件能被嵌套在 swiper、 scroll-view 等容器内,小程序在过去也推出了一些临时的解决方案。但随着小程序生态的发展,开发者对原生组件的使用场景不断扩大,原生组件的这些问题也日趋显现,为了彻底解决原生组件带来的种种限制,我们对小程序原生组件进行了一次重构,引入了「同层渲染」。 相信已经有不少开发者已经在日常的小程序开发中使用了「同层渲染」的原生组件,那么究竟什么是「同层渲染」?它背后的实现原理是怎样的?它是解决原生组件限制的银弹吗?本文将会为你一一解答这些问题。 首先我们先来了解一下小程序原生组件的渲染原理。我们知道,小程序的内容大多是渲染在 WebView 上的,如果把 WebView 看成单独的一层,那么由系统自带的这些原生组件则位于另一个更高的层级。两个层级是完全独立的,因此无法简单地通过使用 z-index 控制原生组件和非原生组件之间的相对层级。正如下图所示,非原生组件位于 WebView 层,而原生组件及 cover-view 与 cover-image 则位于另一个较高的层级: 那么「同层渲染」顾名思义则是指通过一定的技术手段把原生组件直接渲染到 WebView 层级上,此时「原生组件层」已经不存在,原生组件此时已被直接挂载到 WebView 节点上。你几乎可以像使用非原生组件一样去使用「同层渲染」的原生组件,比如使用 view、 image 覆盖原生组件、使用 z-index 指定原生组件的层级、把原生组件放置在 scroll-view、 swiper、 movable-view 等容器内,通过 WXSS 设置原生组件的样式等等。启用「同层渲染」之后的界面层级如下图所示: 你一定也想知道「同层渲染」背后究竟采用了什么技术。只有真正理解了「同层渲染」背后的机制,才能更高效地使用好这项能力。实际上,小程序的同层渲染在
小程序同层渲染原理剖析
 

React Native

React Native 是 2013 年在 Facebook 一个内部的黑客马拉松项目中诞生的,到今年 2022 年新架构出来,已经整整十年了。React Native 上手成本较低。对前端开发者来说,React Native 和前端技术生态重合度很高,学习成本很低;对客户端开发者来说,React Native 省去了大量的编译耗时,并且自带跨端光环, 一份源码可以同时编译成 Android 和 iOS 原生应用,并发布到安卓和苹果应用商店上,同时支持动态更新。
React Native最主要的目的是在前端技术栈的基础上能够优化体验,于是将绘制交回给原生,使用 JavaScript 语言来开发,将 JavaScriptCore 引擎当作虚拟机,将用户描述的 UI,转成对应的原生系统组件,绘制和渲染由原生来实现。
notion image
 
优点
  • 跨端,一次开发多端运行。
  • 成本低易上手,前端转入学习成本很低。
  • 得益于 Web 技术的积累,RN 的生态较完善,框架和自动化工具较完备。
  • 由原生控件组成界面,性能比 WebView 搭建的要好。
  • 支持动态更新,能够降低产品的试错成本。
缺点
  • 实际开发起来,仍然需要掌握一些 Native 技术,对开发人员要求较高。
  • 双端的原生控件特性有差异,无法做到完全的体验一致,处理平台差异性仍然需要耗费极大精力,效果也不尽如人意。
  • JS 和 Native 交互是异步的,渲染时需要 JavaScript 和原生之间通信,在有些场景如拖动可能会因为通信频繁导致卡顿。
  • 第一次加载需要解析JSON + JavaScript,JavaScript 解释执行性能也比原生要差,综合来看体验和原生依然有差距。
  • 由于渲染依赖原生控件,不同平台的控件需要单独维护,并且当系统更新时,社区控件可能会滞后。
 
React Native 优势和劣势很明显,初看起来很美好,似乎可以达到我们想要的效果,一套代码多端运行,代价是牺牲一些体验和性能,事实上它也的确做的很不错,从诞生到现在一直较为活跃,开发者的拥护度也很高,并且有 facebook 背书,一直在不断发展壮大。但是我们也不得不直面他的缺点,如果开发者没有双端原生开发经验,在开发过程中依然会遇到很多问题,并且在平台差异性上,依然很难处理,稍微复杂点的功能,都离不开原生的支持,维护成本较高。2022年,React Native 的新架构正式推出,相对于老架构,新架构在最关键的性能问题上有了非常大的提升,相信这将会为 React Native 开启一个全新的阶段。
 
相关文档
 

Weex

Weex 是阿里巴巴于 2016 年发布的跨平台移动端开发框架,思想及原理和 React Native 类似,底层都是通过原生渲染的,不同是应用层开发语法 (即 DSL,Domain Specific Language):Weex 支持 Vue 语法和 Rax 语法,Rax 的 DSL(Domain Specific Language) 语法是基于 React JSX 语法而创造,而 RN 的 DSL 是基于 React 的,不支持 Vue。
 

Flutter

flutter 是 Google 发布的一个用于创建跨平台、高性能移动应用的框架。它抹平了渲染层的差异,实现了一套自绘引擎,并拥有一套自己的 UI 布局系统,且同时在开发效率上有了很大突破。其实在 Flutter 之前,自绘引擎已经有一个典型的代表,就是 Qt,但是因为生态不好,移动端支持不足,以及使用 C++ 做为开发语言,开发效率低,在近几年势头并不好,地位逐渐被其他的动态化框架取代。Flutter 从一发布就倍数追捧,到 2022年,Flutter 发展飞快,已在业界得到了广泛的关注和认可,在开发者中受到了热烈的欢迎,成为了移动跨端开发中最受欢迎的框架之一。
Flutter 从一开始就抛弃了历史包袱,使用全新的 Dart 语言编写,同时支持 AOT 和 JIT 两种编译方式,而没有采用 HTML/CSS/JavaScript 组合方式开发,在执行效率上明显高于 JavaScriptCore 。
notion image
优点
  • 底层基于 Skia 引擎,自绘制UI,抹平了不同平台的差异。
  • 关注度高,社区发展迅速,并且有谷歌团队开发,不需要担心后续的迭代。
  • 相对于 RN 等其他跨平台方案来说,渲染路径更短,性能更高。
  • 基于热重载功能,开发效率得到了很大程度的提高。
缺点
  • 使用 Dart 语言编写,增加了很多学习成本和开发成本。
  • 默认不支持热更新。
  • 因为使用自研引擎,没有用到系统渲染,所以打出的包相对较大。
  • 发展时间较短,迭代较快,需要考虑版本升级对维护带来的影响。
 
在计算机系统中,图像的显示需要 CPU、GPU 和显示器一起配合完成:CPU 负责图像数据计算,GPU 负责图像数据渲染,而显示器则负责最终图像显示。Flutter 的 UI 线程使用 Dart 来构建视图结构数据,这些数据会在 GPU 线程进行图层合成,随后交给 Skia 引擎加工成 GPU 数据,而这些数据会通过 OpenGL 最终提供给 GPU 渲染。就体验来说,原生开发学习 Flutter 会更好上手,门槛更低,RN 则更加偏向前端开发者。
 
相关文档
 

Native

Native 是指某一个移动平台(比如 iOS 或安卓)所特有的应用,使用相应平台支持的开发工具和语言,并直接调用系统提供的 SDK API。比如 Android 原生应用就是指使用 Java 或 Kotlin 语言直接调用 Android SDK 开发的应用程序;而 iOS 原生应用就是指通过 Objective-C 或 Swift 语言直接调用iOS SDK 开发的应用程序。
优点
  • 可访问平台全部功能。
  • 速度快、性能高、可以实现复杂动画及绘制,整体用户体验好。
  • 定制化强,生态成熟,遇到问题基本上都能有较为成熟的解决方案。
缺点
  • 平台特定,开发成本高,不同平台必须维护不同代码,人力成本较高。
  • 内容固定,动态化弱,大多数情况下,有新功能更新时只能发版。
  • 双端基础组件有差异,某些功能需要容纳不同平台的特性。
 
Native 技术已经有了很多年的积累,社区和生态都十分的成熟,不过面对着各种跨平台框架的冲击,苹果和谷歌也一直在对技术进行更新和升级,谷歌在布局新系统 Fuchsia,苹果这几年也一直在推动最新的框架 SwiftUI,吸收了多个平台的优点,用最少的代码以最快的方式开发应用,声明式布局,学习成本低,并且支持 Apple 全平台,十分令人期待。
 

总结

纵观整个跨平台方案的发展史,各种方案目标基本都是一致的:
  • 减少平台差异性:最大限度减少不同平台上开发的差异性,尽可能减少各平台特有的开发负担;
  • 提高研发效率:从研发效率的角度看,在提高人效比的同时,尽可能提升开发人员在开发过程中的效率,包括编码、调试、运行、测试等多个环节;
  • 原生的性能和体验:尽可能做到和平台原生技术开发一样的性能表现和用户体验,让用户无法感知出差距;
  • 易学的可控技术栈:尽可能让更多原生开发的同学快速学习并掌握,并且无论从技术还是商业角度看,都应该是可控、安全的技术栈。
顺着这个目标,一开始采用原生应用内嵌浏览器控件 WebView 的方式进行 HTML5 页面渲染,并定义 HTML5 与原生代码交互协议,将部分原生系统能力暴露给 HTML5,从而扩展 HTML5 的边界。但是开发者们很快发现承载着大量 Web 标准的 Web 容器过于笨重,以至于性能和体验都达不到与原生同样的水准,在复杂交互和动画上较难实现出优良的用户体验。
为了让体验更好,大家想到能否对笨重的 Web 容器进行功能裁剪,在仅保留必要的 Web 标准和渲染能力的基础上,使得友好的开发体验与稳定的渲染性能保持一个平衡。于是 RN 应运而生,采用原生自带的 UI 组件实现代替了核心的渲染引擎,仍然使用前端友好的 JavaScript 进行开发,整体加载、渲染机制大大简化,并且由原生接管绘制,即将原生系统作为渲染的后端,为依托于 JavaScript 虚拟机的 JavaScript 代码提供所需要的 UI 控件的实体。这种方案解决了不少性能问题,但同时也带来了新的问题。抛开框架本身需要处理大量平台相关的逻辑外,随着系统版本变化和 API 的变化,我们还需要处理不同平台的原生控件渲染能力差异,修复各类奇奇怪怪的 Bug。始终需要 Follow Native 的思维方式,就使得泛 Web 容器框架的跨平台特性被大打折扣。
最新的 Flutter 则开辟了一种全新的思路,即从头到尾重写一套跨平台的 UI 框架,包括渲染逻辑,甚至是开发语言。渲染引擎依靠跨平台的 Skia 图形库来实现,Skia 引擎会将使用 Dart 构建的抽象的视图结构数据加工成 GPU 数据,交由 OpenGL 最终提供给 GPU 渲染,至此完成渲染闭环,因此可以在最大程度上保证一款应用在不同平台、不同设备上的体验一致性。Flutter 也因此成为了目前业界最受关注的跨平台框架。
时代一直在变化,技术也一直在不断的演进,有新的演变和创新是好事,这些变化也给我们带来不同的机遇,做为开发者的我们,不但要参与其中,促进技术的发展,也要吸收前人的经验,不断的提高自己,尝试去抓住下一波属于自己的机遇。
 

如何选择合适的开发方案

关于如何选择开发方案,就目前的情况而言,我认为没有能够称为最优的方案,只有根据自己的业务需求和结合实际情况来选择自己的方案。
在选择跨端方案时,不能只依赖于某几项指标,比如编程语言、性能、技术架构等,来判断是否适合自己团队和产品,更多的还要考虑开发效率、社区支持、构建发布、 DevOps、 CI 支持等工程化方面的指标。在做出选择时,既要着眼于团队现状和所选方案生态,还要考虑技术未来的发展走向。
从技术学习的角度而言,如果是客户端开发,我认为首先应该去学习掌握 Web 前端开发,Web 技术发展非常快,能够学到很多领先于客户端开发的思想和理念,不论将来是哪种技术能够称霸,一定会基于Web 开发的理念之上,所以掌握前端非常重要。之后就是对各种不同方案和技术的底层原理,界面布局,渲染方式,线程调度和数据处理等方面去进行了解,并不需要一定要开发一个项目,我们可以学习他的实现思路,内功比招式更重要,以不变应万变,无论将来技术如何变化,有内功在,就不会感到焦虑。
 
相关文档
移动开发的罗曼蒂克消亡史
作者 | 徐川 编辑 | 小智 对于互联网人来说,这个冬天格外寒冷。 "辛苦一年半,现在要被联合创始人给踢出局了,技术创业真是悲哀。"一个沉寂已久的微信群里,突然冒出了这样一句话。 我看了一眼发消息的人,备注是"勇哥 创业",我心里一紧。 群友被这个消息炸出来,有的看热闹,有的义愤填膺,纷纷要求曝光无良公司。我却不由得回想起当初与勇哥结识的故事。 勇哥大名叫张勇,我与他相识是在 2015 年秋季,当时我正在一个程序员论坛上闲逛,突然一个帖子映入我的眼帘:"搞了个安卓上免安装运行的,准备开源一下"。这个帖子一下子就引起了我的兴趣。 移动开发正是我当时的关注领域,我对智能手机上一切前沿的、好玩的技术都充满好奇。帖子里说,他的这个技术可以通过主 App 启动任意第三方 App,我以前从未听说过这样的技术。 很快,通过朋友介绍,我和帖子的作者张勇搭上了线,他当时是安卓版 360 手机助手的技术负责人,9 月份,我前往酒仙桥 360 总部,与他见了面。 张勇敦厚面相中透着机灵,和大部分程序员不一样,他十分健谈,说起自己开发的 DroidPlugin 眼里带着光。和他聊了两个小时,我确信,这是一项安卓开发黑科技。 中国的技术都是业务驱动的,先有需求,然后研究怎么能做到,DroidPlugin 诞生的背景也是如此。 14 年左右,中国和国外的 App 理念走上了截然不同的两条道路。在国外,一个 App 最多做两三件事,但在中国,一个 App 恨不得装下所有功能,这就是所谓的超级 App。 超级 App 有很多好处,但是,谷歌在设计安卓的时候,没有考虑到存在超级 App 的情况,在安卓早期版本里,一个 App 里只允许存在 65536 个方法,一旦超过就会报错。65536 已经很大了,就和千年虫问题一样,开发安卓的工程师们根本没想到有 App 会需要那么多的方法。
移动开发的罗曼蒂克消亡史
badge