Flutter编译模式

一、编译模式的分类

编程语言达到可运行的过程需要经过编译,因为机器最终认识的是二进制,所以编译就涉及到编译模式,编译模式分为两类:JIT和AOT。

JIT

JIT全称Just In Time(即时编译),典型的例子就是v8,它可以即时编译并运行JavaScript。

JIT模式的优势:可以动态下发和执行代码,不用管用户的机器是什么架构。

JIT模式的劣势:JIT编译器会发给很多时间和内存进行编译,给用户带来的直接给感受就是应用启动慢。

AOT

AOP全称Ahead Of Time(事前编译),典型的例子是C/C++,LLVM或GCC通过编译并生成C/C++的二进制代码,然后这些二进制通过用户安装并取得执行权限后就可以通过进程加载执行。

AOT模式的优势:事前编译好的二进制代码,加载和执行的速度都非常快。(所以编程语言速度排行榜上前列都是AOT编译类语言)

AOT的劣势:编译需要区分用户机器的架构,生成不同架构的二进制代码,除了架构,二进制代码本身也会让用户下载的安装包比较大。还有二进制代码一般需要取得用户权限才可以执行,所以无法在权限比较严格的系统中进行动态更新(如iOS)

二、Dart编译模式

Flutter使用Dart作为变成语言,自然其编译模式也跟Dart的编译模式脱离不了干系,所以我们首先需要了解一下Dart的编译模式。

  • Script 最普通的JIT的编译模式,在PC命令行调用Dart VM执行Dart源代码文件即是这种模式。
  • Script Snapshot: JIT模式,和上一个不同的是,这里载入的已经是token化的Dart代码,提前执行了上一步的lexer的步骤。
  • Application Snapshot: JIT模式,这种模式来源于Dart VM直接载入源码后dump出数据。Dart VM通过这种数据启动会更快。不过这种模式是区分架构的。
  • AOT: AOT模式,直接将Dart源码编译出.S文件,然后通过汇编器生成对应架构的代码。

三、Flutter的编译模式

Flutter完全采用了Dart,按道理说编译模式应该一致,但事实并不似这样,由于Android和iOS平台的生态差异,Flutter也衍生出了非常丰富的编译模式。

  • Script: 同Dart Script模式一致,虽然Flutter支持,但暂未看到使用,毕竟影响启动速度。
  • Script Snapshot: 同Dart Script Snapshot一致,同样支持但未使用,Flutter有大量的视图渲染逻辑,纯JIT模式影响执行速度。
  • Kernel Snapshot: Dart的bytecode模式,与Application Snapshot不同,bytecode模式是不区分架构的,Kernel Snapshot在Flutter项目中也叫Core Snapshot。这种模式可以归类为AOT编译。
  • Core JIT: Dart的一种二进制模式,将指令代码和heap数据打包成文件,然后在VM和isolate启动时载入,直接标记内存可执行,这是一种AOT模式。Core JIT也被叫做AOTBlob。
  • AOT assemblely:即Dart的AOT模式。直接生成汇编源代码文件,由各自平台自行汇编。

可以看出来,Flutter将Dart的编译模式复杂化了,所以为了进一步了解,我们着重从应用开发的各个阶段来进行解读

四、Android的代码编译和执行

开发阶段

在开发阶段,我们需要Flutter的Hot Reload和Hot restart功能,方便UI快速成型。同时,框架层需要比较高的性能来进行视图渲染展现,因此开发模式下,Flutter使用了Kernel Snapshot模式编译

编译产物有:

  • isolate_snapshot_data:用于加速 isolate 启动,业务无关代码,固定,仅和 flutter engine版本有关
  • platform.dill:和 Dart VM 相关的 kernel 代码,仅和 Dart 版本以及 engine编译版本有关。固定,业务无关代码;
  • vm_snapshot_data: 用于加速 Dart VM 启动的产物,业务无关代码,仅和 flutter engine 版本有关;
  • kernel_blob.bin:业务代码产物

生产阶段

在生产阶段,应用需要的是非常快的速度,所以Android和iOS都选用了AOT打包,不过由于平台特性不同,打包模式还是有很大区别的。

Android使用Core JIT编译模式,而iOS则使用AOT Assemblely。

iOS跟Android不同的原因在于:App Store审核条例不允许动态下发可执行二进制代码

Android也可以使用AOT Assemblely,但是这种方式需要支持多架构,增大代码包,而且还需要JNI调用,不如Core JIT的Java API方便,所以Android上默认使用Core JIT打包,而不是AOT Assemblely。

Core JIT 的打包产物有 4 个:isolate_snapshot_data、vm_snapshot_data、isolate_snapshot_instr、vm_snapshot_instr。我们不认识的产物只有 2 个:isolate_snapshot_instr 和 vm_snapshot_instr,其实它俩代表着 VM 和 isolate 启动后所承载的指令等数据。在载入后,直接将该块内存执行即可。

总结

事实上Flutter工程下的ios/android工程本质上依然是一个标准的ios/android工程

iOS:flutter只是通过BuildPhase中添加shell来生成和嵌入App.framework和Flutter.framework

Android:通过gradle来添加flutter.jar和vm/isolate_snapshot_data/instr来将相关代码编译和嵌入原生App

猜你喜欢

转载自blog.csdn.net/qq_33666539/article/details/85631352