Flutter Android 端启动加载流程剖析(v2.0+)
Flutter Android 端的应用启动流程,聚焦于上层 Java/Kotlin 代码实现。不同 Flutter SDK 版本在细节上可能略有差异,但核心流程与原理保持一致。
1. FlutterApplication:启动入口
Android 应用启动遵循 Application → MainActivity 的标准流程。Flutter 项目默认使用 FlutterApplication 或自定义的 Application。
1.1 核心初始化调用
// 核心初始化入口
FlutterInjector.instance().flutterLoader().startInitialization(this);
1.2 FlutterLoader.startInitialization 详解
此方法是 Flutter 引擎初始化的核心,负责准备完整的 Flutter 运行环境。
执行流程与架构设计:
public void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) {
// 单例检查与线程安全校验
if (this.settings != null) return;
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("startInitialization must be called on the main thread");
}
TraceSection.begin("FlutterLoader#startInitialization");
try {
final Context appContext = applicationContext.getApplicationContext();
this.settings = settings;
initStartTimestampMillis = SystemClock.uptimeMillis();
// 关键初始化步骤
flutterApplicationInfo = ApplicationInfoLoader.load(appContext);
// Vsync 同步机制初始化
VsyncWaiter waiter;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
final DisplayManager dm = (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE);
waiter = VsyncWaiter.getInstance(dm, flutterJNI);
} else {
float fps = ((WindowManager) appContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getRefreshRate();
waiter = VsyncWaiter.getInstance(fps, flutterJNI);
}
waiter.init();
// 提交后台初始化任务(IO密集型操作)
Callable<InitResult> initTask = new Callable<InitResult>() {
@Override
public InitResult call() {
TraceSection.begin("FlutterLoader initTask");
try {
// 资源提取与解压
ResourceExtractor resourceExtractor = initResources(appContext);
// 核心库加载
flutterJNI.loadLibrary();
flutterJNI.updateRefreshRate();
// 字体管理器预加载(优化后续启动性能)
executorService.execute(() -> flutterJNI.prefetchDefaultFontManager());
if (resourceExtractor != null) {
resourceExtractor.waitForCompletion();
}
return new InitResult(
PathUtils.getFilesDir(appContext), // 持久化文件目录
PathUtils.getCacheDirectory(appContext), // 缓存目录(系统可清理)
PathUtils.getDataDirectory(appContext) // 引擎数据目录
);
} finally {
TraceSection.end();
}
}
};
initResultFuture = executorService.submit(initTask);
} finally {
TraceSection.end();
}
}
后台任务关键技术解析:
| 关键方法 | 功能说明 | 技术意义 |
|---|---|---|
initResources() | 从 APK 提取资源文件 | 将 assets 中的 flutter_assets 解压到可用文件系统 |
loadLibrary() | 加载 libflutter.so | 加载 Skia 渲染引擎、Dart VM 等核心组件 |
updateRefreshRate() | 同步刷新率信息 | 确保 Flutter 渲染帧率与设备屏幕同步 |
prefetchDefaultFontManager() | 预加载字体管理器 | 减少后续引擎设置的平台线程耗时 |
2. MainActivity:界面入口
Flutter 项目的 MainActivity 继承自 FlutterActivity,承担界面容器角色。
标准实现模式:
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
// 自动生成的插件注册代码
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
}
架构说明:
GeneratedPluginRegistrant.registerWith()由 Flutter 编译工具自动生成- 实现所有已配置插件的自动注册机制
- 确保平台通道(Platform Channels)在引擎启动时可用
3. FlutterActivity:容器实现
3.1 生命周期管理架构
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 主题切换:从启动主题切换到正常主题
switchLaunchThemeForNormalTheme();
super.onCreate(savedInstanceState);
// 委托模式:将核心功能委托给 FlutterActivityAndFragmentDelegate
delegate = new FlutterActivityAndFragmentDelegate(this);
delegate.onAttach(this);
delegate.onRestoreInstanceState(savedInstanceState);
// 生命周期事件分发
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
// 系统级配置
registerOnBackInvokedCallback(); // API 33+ 返回导航回调
configureWindowForTransparency(); // 窗口透明度配置
setContentView(createFlutterView()); // 创建并设置 FlutterView
configureStatusBarForFullscreenFlutterExperience(); // 状态栏适配
}
架构优势:
- 委托模式:分离业务逻辑与界面控制器
- 统一处理:Activity 和 Fragment 实现逻辑统一
- 生命周期标准化:确保 Flutter 引擎与 Android 生命周期同步
4. FlutterActivityAndFragmentDelegate 与 FlutterEngine
4.1 FlutterEngine:核心运行时环境
架构角色:
- Dart 执行环境:托管 Dart VM 运行时
- 渲染协调器:管理 Skia/Impeller 渲染管线
- 平台桥梁:处理 Platform Channels 通信
- 插件管理器:协调原生插件生命周期
4.2 ensureInitializationComplete:关键初始化节点
public void ensureInitializationComplete(@NonNull Context applicationContext, @Nullable String[] args) {
// 状态校验与线程检查
if (initialized) return;
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
}
if (settings == null) {
throw new IllegalStateException("ensureInitializationComplete must be called after startInitialization");
}
TraceSection.begin("FlutterLoader#ensureInitializationComplete");
try {
// 等待后台初始化任务完成
InitResult result = initResultFuture.get();
// 构建引擎启动参数
List<String> shellArgs = new ArrayList<>();
shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");
shellArgs.add("--icu-native-lib-path=" + flutterApplicationInfo.nativeLibraryDir + File.separator + DEFAULT_LIBRARY);
// 构建模式差异化配置
String kernelPath = null;
if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) {
// DEBUG/JIT 模式配置
String snapshotAssetPath = result.dataDirPath + File.separator + flutterApplicationInfo.flutterAssetsDir;
kernelPath = snapshotAssetPath + File.separator + DEFAULT_KERNEL_BLOB;
shellArgs.add("--" + SNAPSHOT_ASSET_PATH_KEY + "=" + snapshotAssetPath);
shellArgs.add("--" + VM_SNAPSHOT_DATA_KEY + "=" + flutterApplicationInfo.vmSnapshotData);
shellArgs.add("--" + ISOLATE_SNAPSHOT_DATA_KEY + "=" + flutterApplicationInfo.isolateSnapshotData);
} else {
// RELEASE/AOT 模式配置
shellArgs.add("--" + AOT_SHARED_LIBRARY_NAME + "=" + flutterApplicationInfo.aotSharedLibraryName);
shellArgs.add("--" + AOT_SHARED_LIBRARY_NAME + "=" + flutterApplicationInfo.nativeLibraryDir +
File.separator + flutterApplicationInfo.aotSharedLibraryName);
// PROFILE 模式特殊处理
if (BuildConfig.PROFILE) {
shellArgs.add("--" + AOT_VMSERVICE_SHARED_LIBRARY_NAME + "=" + VMSERVICE_SNAPSHOT_LIBRARY);
}
}
// 元数据配置读取(AndroidManifest.xml)
ApplicationInfo applicationInfo = applicationContext.getPackageManager()
.getApplicationInfo(applicationContext.getPackageName(), PackageManager.GET_META_DATA);
Bundle metaData = applicationInfo.metaData;
// 堆内存配置
int oldGenHeapSizeMegaBytes = metaData != null ?
metaData.getInt(OLD_GEN_HEAP_SIZE_META_DATA_KEY) : 0;
if (oldGenHeapSizeMegaBytes == 0) {
ActivityManager activityManager = (ActivityManager) applicationContext.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memInfo);
oldGenHeapSizeMegaBytes = (int) (memInfo.totalMem / 1e6 / 2);
}
shellArgs.add("--old-gen-heap-size=" + oldGenHeapSizeMegaBytes);
// 渲染缓存配置
DisplayMetrics displayMetrics = applicationContext.getResources().getDisplayMetrics();
int resourceCacheMaxBytesThreshold = displayMetrics.widthPixels * displayMetrics.heightPixels * 12 * 4;
shellArgs.add("--resource-cache-max-bytes-threshold=" + resourceCacheMaxBytesThreshold);
// 功能开关配置
if (metaData != null && metaData.getBoolean(ENABLE_IMPELLER_META_DATA_KEY, false)) {
shellArgs.add("--enable-impeller");
}
// 执行底层初始化
flutterJNI.init(
applicationContext,
shellArgs.toArray(new String[0]),
kernelPath,
result.appStoragePath,
result.engineCachesPath,
SystemClock.uptimeMillis() - initStartTimestampMillis
);
initialized = true;
} catch (Exception e) {
Log.e(TAG, "Flutter initialization failed.", e);
throw new RuntimeException(e);
} finally {
TraceSection.end();
}
}
4.3 原生引擎连接
private void attachToJni() {
Log.v(TAG, "Attaching to JNI.");
// 建立 JNI 双向通信桥梁
flutterJNI.attachToNative();
if (!isAttachedToJni()) {
throw new RuntimeException("FlutterEngine failed to attach to its native Object reference.");
}
}
4.4 Dart 代码执行:应用启动
public void executeDartEntrypoint(@NonNull DartEntrypoint dartEntrypoint, @Nullable List<String> dartEntrypointArgs) {
// 状态检查防止重复执行
if (isApplicationRunning) {
Log.w(TAG, "Attempted to run a DartExecutor that is already running.");
return;
}
TraceSection.begin("DartExecutor#executeDartEntrypoint");
try {
Log.v(TAG, "Executing Dart entrypoint: " + dartEntrypoint);
// JNI 调用:执行 Dart 代码包
flutterJNI.runBundleAndSnapshotFromLibrary(
dartEntrypoint.pathToBundle, // 代码包路径
dartEntrypoint.dartEntrypointFunctionName, // 入口函数名(默认"main")
dartEntrypoint.dartEntrypointLibrary, // 入口库名(通常为null)
assetManager, // 资源管理器
dartEntrypointArgs // 启动参数
);
isApplicationRunning = true;
} finally {
TraceSection.end();
}
}
DartEntrypoint 参数详解:
| 参数名 | 说明 | 默认值 |
|---|---|---|
pathToBundle | Dart 代码包路径 | Debug: flutter_assets/, Release: AOT 目录 |
dartEntrypointFunctionName | Dart 入口函数名 | "main" |
dartEntrypointLibrary | 入口库名 | null (主库) |
dartEntrypointArgs | 命令行参数 | 可选的参数列表 |
5. 启动流程阶段总结
5.1 阶段一:资源准备期(Application)
- 主线程:环境信息准备、VSync 初始化
- 后台线程:资源解压、原生库加载、字体预加载
5.2 阶段二:引擎初始化期(Activity)
- 参数组装:根据构建模式差异化配置
- JNI 初始化:参数传递至 C++ 层,完成 Dart VM 初始化
- 引擎连接:建立 Java 与 C++ 的双向通信
5.3 阶段三:应用执行期(生命周期)
- Dart 执行:通过
runBundleAndSnapshotFromLibrary启动 Dart 应用 - 界面渲染:完成 Flutter 组件树的构建和渲染
- 插件注册:所有平台插件完成注册和初始化
6. 热更新加载libapp.so
在入口MianActivity实现重写getFlutterShellArgs方法
@Override
public FlutterShellArgs getFlutterShellArgs() {
loadSoFromAssets(); //下载到本地私有目录
FlutterShellArgs supFA = super.getFlutterShellArgs();
// 使用应用私有目录而不是APK安装目录
File libDir = new File(getFilesDir(), "lib");
if (!libDir.exists()) {
libDir.mkdirs();
}
String abi = Build.SUPPORTED_ABIS[0]; // 获取主ABI
File libDir1 = new File(libDir, abi);
if (!libDir1.exists()) {
libDir1.mkdirs();
}
File libFile = new File(libDir1, LIB_NAME);
// 如果文件已存在,直接加载
if (libFile.exists()) {
supFA.add("--aot-shared-library-name=" + libFile.getAbsolutePath()); //如果有libapp文件 ,配置进去,没有则作用默认的
}
return supFA;
}
shellArgs.add("--aot-shared-library-name=" + flutterApplicationInfo.aotSharedLibraryName);
这行代码的作用是告诉 Flutter 引擎在 Release(AOT)模式下,包含预先编译好的本地机器代码的共享库文件(.so)的名称。
6.1. 参数详解
--aot-shared-library-name: 这是一个命令行参数/标志,专门传递给 Flutter 的 C++ 引擎层。引擎在启动时会解析这个参数,从而知道该从哪个动态库文件中加载已经编译好的 Dart 代码。flutterApplicationInfo.aotSharedLibraryName: 这是一个变量,其值是在 Flutter 项目构建时确定的。它存储了编译生成的特定库文件的名称。
6.2. 构建模式与上下文
这个参数仅在 Release 或 Profile 模式下有效(即使用 AOT 编译时)。在 Debug 模式下,Dart 代码是使用 JIT(Just-In-Time)模式运行的,直接从 kernel_blob.bin 文件解释执行,不需要这个参数。
模式对比:
| 构建模式 | 编译方式 | 执行方式 | 关键文件 | 是否需要 --aot-shared-library-name |
|---|---|---|---|---|
| Debug | JIT | 解释执行 | kernel_blob.bin | 否 |
| Profile/Release | AOT | 直接执行原生机器码 | app.so | 是 |
6.3. 文件与路径
-
默认值:在标准的 Flutter 构建中,
aotSharedLibraryName的值通常是libapp.so。lib是 Linux/Android 系统共享库的标准前缀。app是默认的库名,代表你的应用程序。
-
文件内容:这个
.so文件包含了你的 Dart 代码和 Flutter 框架代码被编译成本地机器指令(例如 ARM64、ARMv7 等)的结果。引擎可以直接加载并执行它,效率远高于 JIT 解释执行。
适用版本:Flutter 2.0 及以上