移动端开发基础认识(Android & Flutter)

移动端主要操作系统
iOS
2007年开始,Apple公司开始推出iPhone,同时推出操作系统iOS。iOS在iOS4.0发布前名为iPhone OS。
iOS 系统主要架构如下:
- Cocoa Touch Layer
UI Kit
定义应用程序的基础架构
提供核心功能,例如多任务,触摸操作
包含 EvenKit框架 GameKit框架 MapKit框架 MessageKit框架 等 - Media Service Layer
提供 音频、视频、动画、图像的处理能力
- Core Service Layer
为上层提供一些服务,例如 图形渲染的实现,语音通话的实现。
- Core OS Layer
系统参数 目录服务 磁盘安装卸载事件
Android

关于 JIT 与 AOT
简单的来说就是 “动态解释” 与 “静态编译” 这件事
常见 JIT 的有 JavaScript Python
常见 AOT 的有 C C++
Java 编译过程
JIT (Just in Time)
程序在运行时候一边翻译一边运行
JIT 编译保持了平台无关性,与平台处理相关的东西交给虚拟机。
优点:
程序可以在运行时修改
吞吐量高
可以根据当前程序的运行情况生成最优的机器指令序列
缺点:
启动相对较慢
占用内存较低
程序重新启动后要重新进行优化
AOT (Ahead of Time)
程序在执行前就全部被翻译为机器码
优点:
无需 runtime 就以运行
可以在程序运行初期就达到最高性能
可以显著的加快程序的启动
缺点:
编译时间较长
无法做到对不同硬件架构的跨平台
Android 上的 JIT 与 AOT
Dalvik
在 Android 2.2时候引入了 JIT ,在此之前需要逐条翻译解释执行。
一直到 Android KitKat(4.4) 之前,Android上的虚拟机都是 Dalvik。
这时候使用的是 .dex字节码,是针对Android设备优化后所使用的运行时编译字节码。
在程序运行的过程中进行选择热点代码(经常执行的代码)进行编译或者优化。(JIT)
.odex 是针对dex的优化,用Dalvik虚拟机的Android手机,在安装app的时候,会有一个优化dex的过程,使用dexopt将dex优化的更加高效于运行存储为odex
由于odex中每个类的 id检索链表长度使用了short类型,short 类型能够表示的最大值是 65535,所以一个dex中的方法数不能超过 65535,否则会报错。
Dalvik规定了一个apk只能包含一个dex文件。
ART(Android Runtime)
Android L(5.0) 时候 ART 完全替代了 Dalvik 作为了默认的虚拟机。ART 使用的是 AOT模式。
在 apk 编译的时候会进行预编译,生成OAT文件,仍然以odex保存,但是此时这个文件是可执行文件。
dex、odex均可以通过 dex2oat 来生成 oat文件,以实现兼容性。
此时的代价就是需要耗费更多的存储空间存储 oat文件,apk在安装时候需要做oat的转换,安装应用较耗时。
混合模式
Android N (7.0) 中引入了混合编译模式,同时使用 JIT和AOT。
运行过程中解释执行,
热点函数会被识别并被JIT编译后存储在 jit code cache 中并生成profile文件以记录热点函数的信息。经过 JIT 编译的方法将会记录到Profile配置文件中,Profile会存储在代码缓存中,并会在内存紧张时作为垃圾被回收。
手机进入 IDLE(空闲) 或者 Charging(充电) 状态的时候,系统会扫描 App 目录下的 profile 文件并执行 AOT 过程进行编译。
移动端App开发技术
Native
即原生开发
iOS 平台一般是用 Swift、Objective-C 进行开发
Android 平台一般使用 Kotlin、Java 进行开发
随着目前的发展 iOS上简易实用Swift、Android上使用Kotlin,这将获得更好的开发体验。
同时 Android 上 Jetpack 对 Kotlin 支持较好,Jetpack Compose 仅支持Kotlin。
类似 SwiftUI 也仅支持 Swift。
跨平台
跨平台开发的出现是为了增加代码的复用率,减少要适配多个平台带来的工作量,从而降低开发成本,同时给用户提供在不同平台上一致的体验。
Web
只要是使用的是在 Native应用中内嵌一个浏览器控件 Webview(iOS 为 UIWebView 或 WKWebView,Android 为 WebView)的方式进行 HTML5 页面渲染。
并定义 HTML5 与原生代码交互协议(JS Bridge),将部分原生系统能力暴露给 HTML5,从而扩展 HTML5 的边界。
这种开发模式既有原生应用代码又有 Web 应用代码,因此又被称为 Hybrid 开发模式。由于 HTML5 代码只需要开发一次,就能同时在多个系统运行,因此大大降低了开发成本。
一个完整 HTML5 页面的展示要经历浏览器控件的加载、解析和渲染三大过程,性能消耗要比原生开发增加 N 个数量级。
- 浏览器控件加载 HTML5 页面的 HTML 主文档;
- 加载过程中遇到外部 CSS 文件,浏览器另外发出一个请求,来获取 CSS 文件;
- 遇到图片资源,浏览器也会另外发出一个请求,来获取图片资源。这是异步请求,并不会影响 HTML 文档的加载。
- 加载过程中遇到 JavaScript 文件,由于 JavaScript 代码可能会修改 DOM 树,因此 HTML 文档会挂起渲染(加载解析渲染同步)的线程,直到 JavaScript 文件加载解析并执行完毕,才可以恢复 HTML 文档的渲染线程。
- JavaScript 代码中有用到 CSS 文件中的属性样式,于是阻塞,等待 CSS 加载完毕才能恢复执行。
这是完成 HTML5 页面渲染的最基础的加载过程。加载、解析和渲染这三个过程在实际运行时又不是完全独立的,还会有交叉。也就是说,会存在一边加载,一边解析,一边渲染的现象。

React Native / Weex
这些解决方案优化了 Web 的加载、解析和渲染这三大过程,把影响它们独立运行的 Web 标准进行了裁剪,以相对简单的方式支持了构建移动端页面必要的 Web 标准(如 Flexbox 等),也保证了便捷的前端开发体验。
这些解决方案基本上完全放弃了浏览器控件渲染,而是采用原生自带的 UI 组件实现代替了核心的渲染引擎,仅保持必要的基本控件渲染能力,从而使得渲染过程更加简化,也保证了良好的渲染性能。
也就是说,这些解决方案,仍然采用前端友好的 JavaScript 进行开发,整体加载、渲染机制大大简化,并且由原生接管绘制,即将原生系统作为渲染的后端,为依托于 JavaScript 虚拟机的 JavaScript 代码提供所需要的 UI 控件的实体。
但是 框架本身需要处理大量平台相关的逻辑,,随着系统版本变化和 API 的变化,我们还需要处理不同平台的原生控件渲染能力差异,修复各类奇奇怪怪的 Bug。

Flutter
以 Flutter 为代表的则开辟了一种全新的思路,即从头到尾重写一套跨平台的 UI 框架,包括渲染逻辑,甚至是开发语言。
- 渲染引擎依靠跨平台的 Skia 图形库来实现,Skia 引擎会将使用 Dart 构建的抽象的视图结构数据加工成 GPU 数据,交由 OpenGL 最终提供给 GPU 渲染,至此完成渲染闭环,因此可以在最大程度上保证一款应用在不同平台、不同设备上的体验一致性。
- 而开发语言选用的是同时支持 JIT(Just-in-Time,即时编译)和 AOT(Ahead-of-Time,预编译)的 Dart,不仅保证了开发效率,更提升了执行效率(比使用 JavaScript 开发的泛 Web 容器方案要高得多)。
