在 Flutter 的架构中,Embedder 是连接 Flutter 引擎(Engine)和原生平台的桥梁。它负责将 Flutter 嵌入到不同的平台(如 Android、iOS、Windows、Linux 等),并处理窗口管理、输入事件、生命周期控制等与原生系统相关的任务。Embedder 的启动流程是 Flutter 应用运行的基础,贯穿了资源加载、引擎初始化、渲染视图创建等多个环节。
下面我们详细分析 Embedder 的启动流程。
1. Embedder 的职责
在启动过程中,Embedder 的主要职责包括:
- 加载和初始化 Flutter 引擎(Engine):
- 加载 Flutter 的共享库(如
libflutter.so)。 - 初始化引擎运行时环境,包括 Dart VM 和渲染管道。
- 加载 Flutter 的共享库(如
- 资源加载:
- 提取和加载 Flutter 应用的资源文件(如 Dart 代码、图片等)。
- 窗口管理和渲染:
- 创建窗口和渲染表面(Surface),用于显示 Flutter 的 UI。
- 输入事件处理:
- 捕获原生平台的输入事件(如触摸、键盘)并传递给 Flutter 引擎。
- 生命周期管理:
- 处理应用的启动、暂停、恢复、销毁等生命周期事件。
2. Embedder 启动流程概览
Embedder 的启动流程可以分为以下几个阶段:
- 资源初始化:加载 Flutter 的共享库和应用资源。
- Flutter 引擎初始化:创建并配置
FlutterEngine。 - 渲染视图初始化:创建用于显示 Flutter UI 的渲染视图(如
FlutterSurfaceView)。 - Dart 代码执行:加载 Dart 入口文件并启动 Flutter 框架。
- 运行与渲染:启动渲染循环,显示 Flutter 的首帧。
3. 启动流程的详细分析
3.1 资源初始化
-
入口:
FlutterLoader.startInitialization方法(Android 平台)。 -
关键任务:
- 加载 Flutter 的共享库:
- 在 Android 平台,通过
System.loadLibrary("flutter")加载libflutter.so。 - 在 iOS 平台,
libflutter.dylib是直接链接的,无需显式加载。
- 在 Android 平台,通过
- JNI 接口绑定:
- 加载共享库后,会调用
JNI_OnLoad方法,完成 JNI 接口的注册和绑定。
- 加载共享库后,会调用
- 资源提取:
- 使用
ResourceExtractor提取 Flutter 应用的资源文件(如 Dart AOT 文件、图片等),并将其存储到本地目录。
- 使用
- 加载 Flutter 的共享库:
-
关键代码(Android 平台):
public void startInitialization(Context applicationContext) {
System.loadLibrary("flutter");
ResourceExtractor.extractResources(applicationContext);
}
3.2 Flutter 引擎初始化
-
入口:
FlutterActivityAndFragmentDelegate.onAttach方法。 -
关键任务:
- 创建
FlutterEngine:- 如果指定了缓存的引擎 ID,则从缓存中获取引擎实例。
- 如果未指定缓存,则直接创建新的
FlutterEngine实例。
- 初始化
FlutterJNI:- 调用
FlutterJNI.attachToJni方法,将 JNI 层与 Dart VM 绑定。
- 调用
- 配置引擎:
- 初始化
PlatformPlugin,为 Flutter 提供剪贴板、输入法等原生能力。 - 配置通道(如
MethodChannel、EventChannel)以支持原生交互。
- 初始化
- 创建
-
关键代码(Android 平台):
FlutterEngine flutterEngine = new FlutterEngine(context);
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
);
3.3 渲染视图初始化
-
入口:
FlutterActivityAndFragmentDelegate.onCreateView方法。 -
关键任务:
- 创建渲染视图:
- 根据渲染模式(
RenderMode)创建对应的RenderSurface。 - 渲染模式包括:
FlutterSurfaceView(默认模式,基于 Surface 渲染)。FlutterTextureView(基于 Texture 渲染)。FlutterImageView(基于 Image 渲染)。
- 根据渲染模式(
- 绑定 Flutter 引擎:
- 调用
FlutterView.attachToFlutterEngine方法,将渲染视图与FlutterEngine绑定。
- 调用
- 注册首帧回调:
- 注册
flutterUiDisplayListener,监听 Flutter UI 的首帧渲染完成事件。
- 注册
- 创建渲染视图:
-
关键代码:
FlutterView flutterView = new FlutterView(context);
flutterView.attachToFlutterEngine(flutterEngine);
3.4 Dart 代码执行
-
入口:
FlutterActivityAndFragmentDelegate.doInitialFlutterViewRun方法。 -
关键任务:
- 设置初始路由:
- 通过
NavigationChannel设置 Dart 框架的初始页面路由。
- 通过
- 加载 Dart 入口文件:
- 调用
DartExecutor.executeDartEntrypoint方法,指定 Dart 的入口文件和函数。
- 调用
- 启动 Dart 框架:
- 通过 JNI 调用
nativeRunBundleAndSnapshotFromLibrary方法,加载 Dart 代码并启动 Flutter 框架。
- 通过 JNI 调用
- 设置初始路由:
-
关键代码:
flutterEngine.getNavigationChannel().setInitialRoute("/");
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
);
3.5 运行与渲染
- 入口:
FlutterJNI.onSurfaceChanged和FlutterJNI.onDrawFrame。 - 关键任务:
- 启动渲染循环:
- Flutter 引擎会启动一个渲染循环,每帧都会调用
onDrawFrame方法。
- Flutter 引擎会启动一个渲染循环,每帧都会调用
- 显示首帧:
- 当 Flutter 框架完成首帧绘制时,会通过 JNI 通知 Embedder。
- Embedder 将渲染结果显示到屏幕上。
- 启动渲染循环:
4. 启动流程总结
以下是 Flutter Embedder 启动流程的完整结构:
1. 资源初始化
└── 加载 libflutter.so
└── 提取 Flutter 应用资源
2. Flutter 引擎初始化
└── 创建 FlutterEngine
└── 初始化 FlutterJNI
└── 配置 PlatformPlugin 和通道
3. 渲染视图初始化
└── 创建渲染视图(FlutterSurfaceView 等)
└── 绑定 FlutterEngine
└── 注册首帧回调
4. Dart 代码执行
└── 设置初始路由
└── 加载 Dart 入口文件
└── 启动 Flutter 框架
5. 运行与渲染
└── 启动渲染循环
└── 显示首帧
5. 关键点分析
-
资源加载:
- 资源加载是启动流程的第一步,确保 Flutter 应用的资源(如 Dart AOT 文件)能够被正确加载。
-
FlutterEngine 的核心作用:
FlutterEngine是整个 Flutter 应用的核心,它连接了 Dart VM 和渲染管道。- 它的初始化过程决定了应用的运行环境。
-
渲染视图的选择:
- 根据不同的渲染模式(
FlutterSurfaceView、FlutterTextureView等),可以适配不同的场景需求。
- 根据不同的渲染模式(
-
高效的渲染机制:
- Flutter 的渲染是基于 Vsync 信号的,这确保了渲染与屏幕刷新同步,从而提供流畅的用户体验。
6. 总结
Flutter Embedder 的启动流程是整个 Flutter 应用运行的基础,它将原生平台与 Flutter 引擎无缝连接,确保 Dart 代码和渲染逻辑能够正确运行。通过对启动流程的深入理解,我们可以更好地优化应用的启动性能,并解决与引擎交互的相关问题。
无论是资源加载、引擎初始化还是渲染视图的创建,每个环节都至关重要。掌握这些细节,不仅有助于开发高性能的 Flutter 应用,还能帮助我们更好地理解 Flutter 的跨平台能力和运行机制。