flutter release 版本 调试_深入理解flutter的编译原理与优化

对于开发者而言,什么是Flutter?它是用什么语言编写的,包含哪几部分,是如何被编译,运行到设备上的呢?Flutter如何做到Debug模式Hot Reload快速生效变更,Release模式原生体验的呢?Flutter工程和我们的Android/iOS工程有何差别,关系如何,又是如何嵌入Android/iOS的呢?Flutter的渲染和事件传递机制如何工作?Flutter支持热更新吗?Flutter官方并未提供iOS下的armv7支持,确实如此吗?在使用Flutter的时候,如果发现了engine的bug,如何去修改和生效?构建缓慢或出错又如何去定位,修改和生效呢?

凡此种种,都需要对Flutter从设计,开发构建,到最终运行有一个全局视角的观察。

本文将以一个简单的hello_flutter为例,介绍下Flutter相关原理及定制与优化。

Flutter简介

36048f1a63c5360427befe09f0f3b8e5.png
  • Flutter的架构主要分成三层:Framework,Engine和Embedder。
  • Framework使用dart实现,包括Material Design风格的Widget,Cupertino(针对iOS)风格的
  • Widgets,文本/图片/按钮等基础Widgets,渲染,动画,手势等。此部分的核心代码
  • 是:flutter仓库下的flutter package,以及sky_engine仓库下的io,async,ui(dart:ui库提供了
  • Flutter框架和引擎之间的接口)等package。
  • Engine使用C++实现,主要包括:Skia,Dart和Text。Skia是开源的二维图形库,提供了适用于
  • 多种软硬件平台的通用API。其已作为Google Chrome,Chrome OS,Android, Mozilla
  • Firefox, Firefox OS等其他众多产品的图形引擎,支持平台还包括Windows7+,macOS
  • 10.10.5+,iOS8+,Android4.1+,Ubuntu14.04+等。Dart部分主要包括:Dart Runtime,
  • Garbage Collection(GC),如果是Debug模式的话,还包括JIT(Just In Time)支持。Release
  • 和Profile模式下,是AOT(Ahead Of Time)编译成了原生的arm代码,并不存在JIT部分。Text
  • 即文本渲染,其渲染层次如下:衍生自minikin的libtxt库(用于字体选择,分隔行)。HartBuzz用
  • 于字形选择和成型。Skia作为渲染/GPU后端,在Android和Fuchsia上使用FreeType渲染,
  • 在iOS上使用CoreGraphics来渲染字体。
  • Embedder是一个嵌入层,即把Flutter嵌入到各个平台上去,这里做的主要工作包括渲染
  • Surface设置,线程设置,以及插件等。从这里可以看出,Flutter的平台相关层很低,平台(如
  • iOS)只是提供一个画布,剩余的所有渲染相关的逻辑都在Flutter内部,这就使得它具有了很好
  • 的跨端一致性。

Flutter工程结构
本文使用开发环境为flutter beta v0.3.1,对应的engine commit:09d05a389。

以hello_flutter工程为例,Flutter工程结构如下所示:

2fd6d245db81e882f1f5063664656614.png
  • 其中ios为iOS部分代码,使用CocoaPods管理依赖,android为Android部分代码,使用
  • Gradle管理依赖,lib为dart代码,使用pub管理依赖。类似iOS中Cocoapods对应的Podfile
  • 和Podfile.lock,pub下则是pubspec.yaml和pubspec.lock。

Flutter模式

  • 对于Flutter,它支持常见的debug,release,profile等模式,但它又有其不一样。
  • Debug模式:对应了Dart的JIT模式,又称检查模式或者慢速模式。支持设备,模拟器
  • (iOS/Android),此模式下打开了断言,包括所有的调试信息,服务扩展和Observatory等调
  • 试辅助。此模式为快速开发和运行做了优化,但并未对执行速度,包大小和部署做优化。
  • Debug模式下,编译使用JIT技术,支持广受欢迎的亚秒级有状态的hot reload。
  • Release模式:对应了Dart的AOT模式,此模式目标即为部署到终端用户。只支持真机,不包
  • 括模拟器。关闭了所有断言,尽可能多地去掉了调试信息,关闭了所有调试工具。为快速启
  • 动,快速执行,包大小做了优化。禁止了所有调试辅助手段,服务扩展。
  • Profile模式:类似Release模式,只是多了对于Profile模式的服务扩展的支持,支持跟踪,以
  • 及最小化使用跟踪信息需要的依赖,例如,observatory可以连接上进程。Profile并不支持模
  • 拟器的原因在于,模拟器上的诊断并不代表真实的性能。
  • 鉴于Profile同Release在编译原理等上无差异,本文只讨论Debug和Release模式。
  • 事实上flutter下的iOS/Android工程本质上依然是一个标准的iOS/Android的工程,flutter只
  • 是通过在BuildPhase中添加shell来生成和嵌入App.framework和Flutter.framework(iOS),通
  • 过gradle来添加flutter.jar和vm/isolate_snapshot_data/instr(Android)来将Flutter相关代码
  • 编译和嵌入原生App而已。因此本文主要讨论因flutter引入的构建,运行等原理。编译target
  • 虽然包括arm,x64,x86,arm64,但因原理类似,本文只讨论arm相关(如无特殊说明,android
  • 默认为armv7)。

Flutter代码的编译与运行(iOS)
Release模式下的编译
release模式下,flutter下iOS工程中dart代码构建链路如下所示:

50cea2c7098c9d3d96ce3ea28d11dc77.png
  • 其中gen_snapshot是dart编译器,采用了tree shaking(类似依赖树逻辑,可生成最小包也
  • 因而在Flutter中禁止了dart支持的反射特性)等技术,用于生成汇编形式的机器代码,再通过
  • xcrun等编译工具链生成最终的App.framework。换句话说,所有的dart代码,包括业务代
  • 码,三方package代码,它们所依赖的flutter框架代码,最终将会变成App.framework。
  • tree shaking功能位于gen_snapshot中,对应逻辑参见:
  • engine/src/third_party/dart/runtime/vm/compiler/aot/http://precompiler.cc
  • dart代码最终对应到App.framework中的符号如下所示:

ed8ed4caa02bb17940ff56a3b1ec2096.png
  • 事实上,类似Android Release下的产物(见下文),App.framework也包含了
  • kDartVmSnapshotData,kDartVmSnapshotInstructionskDartIsolateSnapshotData,
  • kDartIsolateSnapshotInstructions四个部分。为什么iOS使用App.framework这种方式而
  • 不是Android的四个文件的方式呢?原因在于在iOS下,因为系统的限制,Flutter引擎不够
  • 在运行时将某内存页标记为可执行,而Android是可以的。
  • Flutter.framework对应了Flutter架构中的engine部分,以及Embedder。实际中
  • Flutter.framework位于flutter仓库的/bin/cache/artifacts/engine/ios*下,默认从google仓
  • 库拉取。当需要自定义修改的时候,可通过下载engine源码,利用Ninja构建系统来生成。
  • Flutter相关代码的最终产物是:App.framework(dart代码生成)和Flutter.framework(引擎)。
  • 从Xcode工程的视角看,Generated.xcconfig描述了Flutter相关环境的配置信息,然后
  • Runner工程设置中的Build Phases新增的xcode_backend.sh实现了Flutter.framework的拷
  • 贝(从Flutter仓库的引擎到Runner工程根目录下的Flutter目录)与嵌入和App.framework的编
  • 译与嵌入。最终生成的Runner.app中Flutter相关内容如下所示:

071965fabf72e8e5b4bb9b90ac41a29c.png
  • 其中flutter_assets是相关的资源,代码则是位于Frameworks下的App.framework和
  • Flutter.framework。
  • Debug模式下的编译

  • Debug模式下flutter的编译,结构类似Release模式,差异主要表现为两点:

1.Flutter.framework

因为是Debug,此模式下Framework中是有JIT支持的,而在Release模式下并没有JIT部分。

2.App.framework

  • 不同于AOT模式下的App.framework是Dart代码对应的本地机器代码,JIT模式下,
  • App.framework只有几个简单的API,其Dart代码存在于snapshot_blob.bin文件里。这部分
  • 的snapshot是脚本快照,里面是简单的标记化的源代码。所有的注释,空白字符都被移除,
  • 常量也被规范化,也没有机器码,tree shaking或者是混淆。
  • App.framework中的符号表如下所示:

6084a6fd6bad3507bb981a3f862bd082.png

对Runner.app/flutter_assets/snapshot_blob.bin执行strings命令可以看到如下内容:

7616f96e4b4882064398b1fa767b86ba.png
  • Debug模式下main入口的调用堆栈如下:
  • debug isolate main callstack
  • Flutter代码的编译与运行(Android)
  • 鉴于Android和iOS除了部分平台相关的特性外,其他逻辑如Release对应AOT,Debug对应
  • JIT等均类似,此处只涉及两者不同。
  • Release模式下的编译

  • release模式下,flutter下Android工程中dart代码整个构建链路如下所示:

e60448911b6dff211033c68560bc069b.png
  • 其中vm/isolate_snapshot_data/instr内容均为arm指令,将会在运行时被engine载入,并标
  • 记vm/isolate_snapshot_instr为可执行。vm_中涉及runtime等服务(如gc),用于初始化
  • DartVM,调用入口见Dart_Initialize(dart_api.h)。isolate__则是对应了我们的App代码,用
  • 于创建一个新的isolate,调用入口见Dart_CreateIsolate(dart_api.h)。flutter.jar类似iOS的
  • Flutter.framework,包括了engine部分的代码(Flutter.jar中的libflutter.so),以及一套将
  • Flutter嵌入Android的类和接口(FlutterMain,FlutterView,FlutterNativeView等)。实际中
  • flutter.jar位于flutter仓库的/bin/cache/artifacts/engine/android*下,默认从google仓库
  • 拉取。当需要自定义修改的时候,可通过下载engine源码,利用Ninja构建系统来生成flutter.jar。

正在跳转(iOS交流裙 密码:123)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值