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的类图:
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文件结构
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 engine就完成了
总结:
这一篇主要分析了Android程序在启动时如何初始化Flutter相关资源, 主要由FlutterMain代理到FlutterLoader来负责,执行步骤就是以上介绍的7步操作,不是很难理解。
理解错误的地方,望各位大牛指教。