在调研 Flutter 动态化方案的时候,须要了解 Flutter 加载 dart 产物的流程,阅读了一部分源码,顺便也读了初始化相关的代码。因而梳理了一遍 Flutter 的初始化流程java
flutter的源码下载地址在 github 上能够找到,具体地址: github-flutter/engineandroid
先从 Android 的入口开始看c++
在 FlutterAppliation
的 onCreate
中调用了git
FlutterMain.startInitialization(this);
复制代码
跟进去咱们会看到调用了 startInitialization
方法,最后会顺序调用这几个方法github
initConfig(applicationContext);
initAot(applicationContext);
initResources(applicationContext);
复制代码
咱们查看 initResources
方法如图shell
这里咱们能够看到实际加载了assets里面的flutter资源。而且会把资源 copy 到本地的路径。这里不作深究。FlutterMan
的初始化基本包括了性能优化
3 个部分app
继续看 Flutter
的 View
的初始化:ide
以 FlutterActivity
为例,在 onCreate
中会调用到 FlutterActivityDelegate
的对应方法,最终调用 FlutterView
的 runFromBundle
方法函数
public void runFromBundle(FlutterRunArguments args) {
this.assertAttached();
this.preRun();
this.mNativeView.runFromBundle(args);
this.postRun();
}
复制代码
跟踪这段代码,会调用 FlutterNativeView
的 nativeRunBundleAndSnapshotFromLibrary
方法。
这里会继续进行 jni
层的调用,查看 platform_view_android_jni.cc
{
.name = "nativeRunBundleAndSnapshotFromLibrary",
.signature = "(J[Ljava/lang/String; Ljava/lang/String;"
"Ljava/lang/String;Landroid/content/res/AssetManager;)V",
.fnPtr = reinterpret_cast<void*> (shell::RunBundleAndSnapshotFromLibrary),
},
复制代码
查看 RunBundleAndSnapshotFromLibrary
,这里删除了一些咱们不关心的逻辑
static void RunBundleAndSnapshotFromLibrary(JNIEnv* env,
jobject jcaller,
jlong shell_holder,
jobjectArray jbundlepaths,
jstring jEntrypoint,
jstring jLibraryUrl,
jobject jAssetManager) {
auto asset_manager = std::make_shared<blink::AssetManager>();
for (const auto& bundlepath :
fml::jni::StringArrayToVector(env, jbundlepaths)) {
const auto file_ext_index = bundlepath.rfind(".");
if (bundlepath.substr(file_ext_index) == ".zip") {
asset_manager->PushBack(
std::make_unique<blink::ZipAssetStore>(bundlepath));
} else {
asset_manager->PushBack(
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
bundlepath.c_str(), false, fml::FilePermission::kRead)));
const auto last_slash_index = bundlepath.rfind("/", bundlepath.size());
if (last_slash_index != std::string::npos) {
auto apk_asset_dir = bundlepath.substr(
last_slash_index + 1, bundlepath.size() - last_slash_index);
asset_manager->PushBack(std::make_unique<blink::APKAssetProvider>(
env, // jni environment
jAssetManager, // asset manager
std::move(apk_asset_dir)) // apk asset dir
);
}
}
}
auto isolate_configuration = CreateIsolateConfiguration(*asset_manager);
RunConfiguration config(std::move(isolate_configuration),
std::move(asset_manager));
ANDROID_SHELL_HOLDER->Launch(std::move(config));
复制代码
首先会对资源路径进行处理 会分为 zip
包或者文件夹进行分别处理。最终会调用常量ANDROID_SHELL_HOLDER
的 Launch
函数.
最终走到 engine
的 Run
函数。
这里有 2 个函数比较重要,先是 IsolateConfiguration::PrepareIsolate
, 而后是 RunFromLibrary
或者 Run
函数
跟到 PrepareAndLaunchIsolate
函数,查看源码
bool IsolateConfiguration::PrepareIsolate(blink::DartIsolate& isolate) {
if (isolate.GetPhase() != blink::DartIsolate::Phase::LibrariesSetup) {
FML_DLOG(ERROR)
<< "Isolate was in incorrect phase to be prepared for running.";
return false;
}
return DoPrepareIsolate(isolate);
}
复制代码
而有 DoPrepareIsolate
函数的类 Configuration
类有3个
他们分别会调用 DartIsolate
的
这2个方法的一个,能够看到这里的prepare
操做分红了 预先加载的代码 和 从内核获取 2种
至于 RunFromLibrary
函数和 Run
函数
咱们能看到他们最终都会调用 dart:isolate
和 _startMainIsolate
的逻辑:
Dart_Handle isolate_lib = Dart_LookupLibrary(tonic::ToDart("dart:isolate"));
if (tonic::LogIfError(Dart_Invoke(
isolate_lib, tonic::ToDart("_startMainIsolate"),
sizeof(isolate_args) / sizeof(isolate_args[0]), isolate_args))) {
return false;
}
复制代码
这里说明咱们正在执行调用 Dart
的入口方法。而 Run
和 RunFromLibrary
的区别,则是若是咱们传入了 entrypoint
参数去进行 Flutter 的 bundle 初始化的时候,则会去加载咱们制定的 library。
到这里, Flutter 的初始化流程就就简单的分析了一遍。大体能够总结成三个部分
初始化的逻辑比较复杂,对后续一些初始化相关的性能优化应该也会有不小的启发。FlutterMain
中对资源的处理和写入本地的逻辑也给 Android 端研究 Flutter 动态化提供了基础。
不少 bundle 加载和后续初始化的逻辑也尚未彻底弄清楚和深刻研究。有兴趣的朋友能够一块儿研究,共同探讨。