Flutter应用启动流程分析(一)

Flutter启动流程

  • Flutter应用启动流程分析(一)

Flutter应用启动流程分析(一)

1、FlutterApplication

废话不说直奔应用入口FlutterApplication类:

public class FlutterApplication extends Application {
    @Override
    @CallSuper
    public void onCreate() {
        super.onCreate();
        FlutterMain.startInitialization(this);
    }

    private Activity mCurrentActivity = null;
    public Activity getCurrentActivity() {
        return mCurrentActivity;
    }
    public void setCurrentActivity(Activity mCurrentActivity) {
        this.mCurrentActivity = mCurrentActivity;
    }
}

简单的不能再简单了开发应用时我们可继承此类,来看onCreate方法中调用了FlutterMain的startInitialization()进行初始化Flutter engine,属性mCurrentActivity保存了当前正在前台展示的Activity引用。

2、FlutterMain

接着往下看看FlutterMain类中都做了什么,定位到FlutterMain的startInitialization方法

 public static void startInitialization(@NonNull Context applicationContext) {
        if (isRunningInRobolectricTest) {
            return;
        }
        FlutterLoader.getInstance().startInitialization(applicationContext);
    }

先对isRunningInRobolectricTest变量做判断是否进行下面的初始化操作,变量值初始化为false(当前看此变量没有重新调用赋值的地方,会一直为false,以后看看在别的有没有使用到),所以一定会走到下面的代码执行。发现最终交由FlutterLoader来执行,再看别的方法也是交由FlutterLoader来执行的,好了我们知道了FlutterMain根本没有做实质性的操作,就是一个空壳子,一个静态代理类而已。看看FlutterMain的类图:

Flutter应用启动流程分析(一)_第1张图片
FlutterMain对外提供的都是静态方法,它们最终都会交由FlutterLoader来执行。

3、FlutterLoader
顺着FlutterMain中的startInitialization方法来到FlutterLoader的startInitialization看看它做了什么:

    public void startInitialization(@NonNull Context applicationContext) {
        startInitialization(applicationContext, new Settings());
    }
    
    public void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) {
        // Do not run startInitialization more than once.
        if (this.settings != null) {
          return;
        }
        if (Looper.myLooper() != Looper.getMainLooper()) {
          throw new IllegalStateException("startInitialization must be called on the main thread");
        }

        this.settings = settings;

        long initStartTimestampMillis = SystemClock.uptimeMillis();
        initConfig(applicationContext);
        initResources(applicationContext);

        System.loadLibrary("flutter");

        VsyncWaiter
            .getInstance((WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE))
            .init();

        // We record the initialization time using SystemClock because at the start of the
        // initialization we have not yet loaded the native library to call into dart_tools_api.h.
        // To get Timeline timestamp of the start of initialization we simply subtract the delta
        // from the Timeline timestamp at the current moment (the assumption is that the overhead
        // of the JNI call is negligible).
        long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
        FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);
    }

后续调用了startInitialization的两个参数的重载方startInitialization(@NonNull Context applicationContext, @NonNull Settings settings),settings类就一个设置-----设置log输出的标签名称(默认没有设置)。方法注释说道:将加载Flutter引擎的本机库flutter.so以启用后续的JNI调用。还将查找解压打包在apk中的dart资源。方法只会被调用一次。下面看看方法具体是怎么干这件事的:
步骤很清晰,逐一屡一下
1、settings属性是否赋值来确定方法是否执行过;
2、方法必须在主线程中执行,否则抛异常退出(这也造成了应用在启动时慢一些);
3、初始化配置;
4、初始化资源;
5、加载flutter.so动态库;
6、VsyncWaiter 应该是同步帧率相关的操作(待研究…);
7、记录初始化耗时时间
着重看3、4、5步,

initConfig:通过从manifest XML文件获取Flutter配置值来初始化这些值

 private void initConfig(@NonNull Context applicationContext) {
        Bundle metadata = getApplicationInfo(applicationContext).metaData;

        // There isn't a `` tag as a direct child of `` in
        // `AndroidManifest.xml`.
        if (metadata == null) {
            return;
        }

        aotSharedLibraryName = metadata.getString(PUBLIC_AOT_SHARED_LIBRARY_NAME, DEFAULT_AOT_SHARED_LIBRARY_NAME);
        flutterAssetsDir = metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, DEFAULT_FLUTTER_ASSETS_DIR);

        vmSnapshotData = metadata.getString(PUBLIC_VM_SNAPSHOT_DATA_KEY, DEFAULT_VM_SNAPSHOT_DATA);
        isolateSnapshotData = metadata.getString(PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY, DEFAULT_ISOLATE_SNAPSHOT_DATA);
    }

从AndroidManifest中读取meta-data配置参数。主要是指定编译后生成的代码文件的名称,主要包括
io.flutter.embedding.engine.loader.FlutterLoader.aot-shared-library-name 默认值:libapp.so
io.flutter.embedding.engine.loader.FlutterLoader.flutter-assets-dir 默认值:flutter_assets
io.flutter.embedding.engine.loader.FlutterLoader.vm-snapshot-data 默认值:vm_snapshot_data
io.flutter.embedding.engine.loader.FlutterLoader.isolate-snapshot-data 默认值:isolate_snapshot_data
apk文件结构
Flutter应用启动流程分析(一)_第2张图片
Flutter应用启动流程分析(一)_第3张图片
debug 和 release 编译出来的apk目录结构是不同的,release 模式下,不使用 snapshot 文件,而使用 libapp.so,生成什么文件区别于两种编译模式,JIT和AOT。

initResources:提取apk中的资源文件复制到应用本地文件中。

 private void initResources(@NonNull Context applicationContext) {
        new ResourceCleaner(applicationContext).start();

        if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) {
            final String dataDirPath = PathUtils.getDataDirectory(applicationContext);
            final String packageName = applicationContext.getPackageName();
            final PackageManager packageManager = applicationContext.getPackageManager();
            final AssetManager assetManager = applicationContext.getResources().getAssets();
            resourceExtractor = new ResourceExtractor(dataDirPath, packageName, packageManager, assetManager);

            // In debug/JIT mode these assets will be written to disk and then
            // mapped into memory so they can be provided to the Dart VM.
            resourceExtractor
                .addResource(fullAssetPathFrom(vmSnapshotData))
                .addResource(fullAssetPathFrom(isolateSnapshotData))
                .addResource(fullAssetPathFrom(DEFAULT_KERNEL_BLOB));

            resourceExtractor.start();
        }
    }

1、ResourceCleaner清理应用cache目录下以.org.chromium.Chromium.开头的文件,会延迟5秒执行。
2、在DEBUG或者在JIT_RELEASE模式下安装Flutter资源,主要由ResourceExtractor来异步执行资源文件的解压缩操作,最终会将apk中assets中的Dart资源文件安装到应用目录app_flutter目录下,这里不做深究了,毕竟我们的目的是针对release编译版本的。只要知道安装flutter资源就是拷贝assets目录到指定应用目录中。
Flutter应用启动流程分析(一)_第4张图片
至此应用初始化加载Flutter engine就完成了
总结:
这一篇主要分析了Android程序在启动时如何初始化Flutter相关资源, 主要由FlutterMain代理到FlutterLoader来负责,执行步骤就是以上介绍的7步操作,不是很难理解。

理解错误的地方,望各位大牛指教。

你可能感兴趣的:(Flutter应用启动流程分析(一))