Flutter Android 端启动加载流程及热更新加载so文件

257 阅读6分钟

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 参数详解:

参数名说明默认值
pathToBundleDart 代码包路径Debug: flutter_assets/, Release: AOT 目录
dartEntrypointFunctionNameDart 入口函数名"main"
dartEntrypointLibrary入口库名null (主库)
dartEntrypointArgs命令行参数可选的参数列表

5. 启动流程阶段总结

5.1 阶段一:资源准备期(Application)

  • 主线程:环境信息准备、VSync 初始化
  • 后台线程:资源解压、原生库加载、字体预加载

5.2 阶段二:引擎初始化期(Activity)

  • 参数组装:根据构建模式差异化配置
  • JNI 初始化:参数传递至 C++ 层,完成 Dart VM 初始化
  • 引擎连接:建立 Java 与 C++ 的双向通信

5.3 阶段三:应用执行期(生命周期)

  • Dart 执行:通过 runBundleAndSnapshotFromLibrary 启动 Dart 应用
  • 界面渲染:完成 Flutter 组件树的构建和渲染
  • 插件注册:所有平台插件完成注册和初始化

deepseek_mermaid_20250827_10ac34.png

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
DebugJIT解释执行kernel_blob.bin
Profile/ReleaseAOT直接执行原生机器码app.so
6.3. 文件与路径
  • 默认值:在标准的 Flutter 构建中,aotSharedLibraryName 的值通常是 libapp.so

    • lib 是 Linux/Android 系统共享库的标准前缀。
    • app 是默认的库名,代表你的应用程序。
  • 文件内容:这个 .so 文件包含了你的 Dart 代码和 Flutter 框架代码被编译成本地机器指令(例如 ARM64、ARMv7 等)的结果。引擎可以直接加载并执行它,效率远高于 JIT 解释执行。


适用版本:Flutter 2.0 及以上