目录
介绍
一、Flutter 与 Dart
Flutter 是一种用于构建高性能、跨平台移动应用、Web 应用和桌面应用的开源框架.
Flutter 框架,它提供了一组工具、库和组件,用于构建用户界面、处理用户输入、管理状态等。
Dart 是 Flutter 的官方编程语言,具有现代编程语言的特性,如强类型、异步编程支持、面向对象特性等。
Dart 作为其主要编程语言,你会使用 Dart 来编写应用程序的逻辑、业务逻辑、界面交互等。
二、Flutter框架设计
1 框架层:
我们编写的dart代码,包括使用三方的 package、plugin最终会被编译成对应平台的二进制代码(AOT模式)或者.dill(JIT模式下的中间代码)
在 Flutter 中,应用程序的 UI 是通过构建不同的小部件(Widgets)来创建的即Widgets驱动。
在iOS中dart代码编译后就是App.framework
2 引擎层:
作用一:Dart运行时:
载入并执行编译后的 Dart 代码(AOT模式),载入并解释执行.dill中间代码(JIT模式)
作用二:绘制渲染:
通过 Skia 引擎实现真正的绘制和渲染
FlutterViewController 是一个 iOS 原生的视图控制器,绑定了 Flutter 引擎的实例。
并且FlutterViewController.view.layer为渲染好的Flutter UI提供入口点。
作用三:平台通道:
channel, Dart 和原生平台(如 iOS、Android)之间的双向通信。
作用四:事件处理:
处理来自操作系统的事件(如触摸事件),并将这些事件传递给 Dart 层进行处理。
作用五:生命周期管理:
管理应用的生命周期事件,如应用启动、暂停、恢复。
这些事件会触发相应的 Dart 回调函数,使得应用能够响应生命周期的变化。
在iOS中引擎层代码编译后就是flutter.framework
3 嵌入层
Embedder,即嵌入层。
Flutter 最终渲染、交互是要依赖其所在平台的操作系统 API,嵌入层主要是将 Flutter 引擎 ”安装“ 到特定平台上。
嵌入层采用了当前平台的语言编写,例如 Android 使用的是 Java 和 C++, iOS 和 macOS 使用的是 Objective-C 和 Objective-C++,Windows 和 Linux 使用的是 C++。
Flutter 代码可以通过嵌入层,以模块方式集成到现有的应用中,也可以作为应用的主体。
Flutter 本身包含了各个常见平台的嵌入层,假如以后 Flutter 要支持新的平台,则需要针对该新的平台编写一个嵌入层。比如Harmony
需要注意的是:
Flutter 的嵌入层代码主要位于 Flutter 引擎的仓库中,具体分布在几个不同的目录中。
shell/platform/android:包含 Android 平台相关的嵌入层实现代码。
shell/platform/darwin/ios:包含 iOS 平台相关的嵌入层实现代码
要想更详细的了解flutter,可以参考《Flutter实战·第二版》中的章节:
1.2 初识 Flutter
三、flutter的 AOT 和 JIT 模式
一套代码运行在多个平台,包括 iOS、Android、Web 和桌面平台。
这种能力是由 Dart 语言和 Flutter 框架的设计支持实现的。
1、语言跨平台有两种方式:
1.1 类似c++,通过编译器编译成可以在该平台运行的二进制代码。
1.2 类似java,平台安装java虚拟机来运行java编译出的中间代码
java - 中间代码 - java vm - 可以运行在平台的二进制
dart语言的跨平台结合了上面的两种方式
2、AOT模式
AOT = Ahead-of-Time(预先编译)
指的是Dart 代码在构建阶段就被编译成特定平台的原生机器码,而不是等到运行时再编译(JIT)。
举个具体例子:
void main() {
runApp(MyApp());
}
构建 iOS 发布版时:
1、Flutter 会把 main() 及其依赖的所有 Dart 代码 AOT 编译成机器码(flutter build ios –release)
2、编译后的结果打包到 Flutter 应用的资源中(例如 App.framework)
3、应用启动后,iOS 的原生代码创建 FlutterEngine,并启动
4、FlutterEngine 会:
加载这个 AOT 代码段(比如内存映射进来)
直接从 AOT 编译好的 main() 开始执行
3、JIT模式
JIT = Just-In-Time(即时编译)
Dart 代码在应用运行时通过 Dart VM 的 JIT 编译器 编译成机器码并执行
Flutter Engine 内部集成了 Dart VM,它会在运行时加载、解析和执行 Dart 源代码或字节码。
举个具体例子:
void main() {
runApp(MyApp());
}
1、Flutter 将 Dart 代码(main() 及其依赖)编译为 Kernel 字节码(.dill 文件)
比如 main.dill → kernel_blob.bin
这是一种中间格式,方便动态加载和 JIT 编译
2、字节码(kernel_blob.bin)被打包到应用资源中:
路径:App.framework/flutter_assets/kernel_blob.bin
同时包括 Dart assets、字体、图片等资源
3、应用启动后,iOS 的原生代码创建 FlutterEngine,并启动
4、FlutterEngine 启动时会:
初始化 Dart VM
查找并加载 flutter_assets/kernel_blob.bin
从 .dill 中定位 main()并开始解释执行
我们可以通过 App.framework/flutter_assets/中是否有 kernel_blob.bin 文件来判断当前是否运行在JIT模式
两个项目
1、flutter工程项目
开发者从 Flutter 的官方网站下载 Flutter SDK,SDK 中包含了 Flutter 框架、Dart SDK 以及 Flutter 引擎的二进制文件。
引擎在flutter sdk中的位置
/opt/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64/Flutter.framewor
查看当前的engine的版本
/opt/flutter/bin/internal/engine.version
xy:调试器、编译器、命令行工具应该也在flutter sdk中
2、engine工程项目
engine工程
这是引擎层的源码,我们可以调试引擎源码或修改源码来使用我们自定义的flutter engine
flutter 的嵌入层代码也位于这个仓库中
相关指令
flutter doctor
环境诊断
如果没有看到iOS的模拟器,可以运行flutter doctor检查问题,然后按提示进行操作
切换了xcode的默认命令行工具可能会导致找不到iOS的模拟器
flutter clean
清缓存
flutter pub get
获取第三方包依赖,特殊使用场景
跨平台技术
技术类型 | UI渲染方式 | 性能 | 开发效率 | 动态化 | 框架代表 |
H5 + 原生 | WebView渲染 | 一般 | 高 | 支持 | Cordova、Ionic |
JavaScript + 原生渲染 | 原生控件渲染 | 好 | 中 | 支持 | RN、Weex |
自绘UI + 原生 | 调用系统API渲染 | 好 | Flutter高, Qt低 | 默认不支持 | Qt、Flutter |
H5+原生
混合应用的优点是:动态内容可以用 H5开发,而H5是Web 技术栈,Web技术栈生态开放且社区资源丰富,整体开发效率高。
缺点是性能体验不佳,对于复杂用户界面或动画,WebView 有时会不堪重任。
调用系统能力比如蓝牙或相机需要借助jsbridge。
JavaScript + 原生渲染
优点:
采用 Web 开发技术栈,社区庞大、上手快、开发成本相对较低。
原生渲染,性能相比 H5 提高很多。
动态化较好,支持热更新。
缺点:
渲染时需要 JavaScript 和原生之间通信,在有些场景如拖动可能会因为通信频繁导致卡顿。
JavaScript 为脚本语言,执行时需要解释执行
由于渲染依赖原生控件,不同平台的控件需要单独维护,并且当系统更新时,社区控件可能会滞后
重要的几个概念:
DOM树(控件树)、虚拟DOM树、响应式编程、JIT、AOT
自绘UI + 原生
优点:
性能高;由于自绘引擎是直接调用系统API来绘制UI,所以性能和原生控件接近
灵活、组件库易维护、UI外观保真度和一致性高;由于UI渲染不依赖原生控件,也就不需要根据不同平台的控件单独维护一套组件库,所以代码容易维护
缺点:
动态性不足;
行者常至,为者常成!