在調研 Flutter 動態化方案的時候,需要了解 Flutter 載入 dart 產物的流程,閱讀了一部分原始碼,順便也讀了初始化相關的程式碼。於是梳理了一遍 Flutter 的初始化流程
flutter的原始碼下載地址在 github 上可以找到,具體地址: github-flutter/engine
FLutterMain的初始化
先從 Android 的入口開始看
在 FlutterAppliation
的 onCreate
中呼叫了
FlutterMain.startInitialization(this);
複製程式碼
跟進去我們會看到呼叫了 startInitialization
方法,最後會順序呼叫這幾個方法
initConfig(applicationContext);
initAot(applicationContext);
initResources(applicationContext);
複製程式碼
我們檢視 initResources
方法如圖
這裡我們可以看到實際載入了assets裡面的flutter資源。並且會把資源 copy 到本地的 路徑。這裡不做深究。FlutterMan
的初始化基本包括了
- 初始化配置
- 初始化 AOT 編譯
- 初始化資源
3 個部分
繼續看 Flutter
的 View
的初始化:
FLutterView的初始化
以 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個
- AppSnapshotIsolateConfiguration
- KernelIsolateConfiguration
- KernelListIsolateConfiguration
他們分別會呼叫 DartIsolate
的
- PrepareForRunningFromPrecompiledCode
- PrepareForRunningFromKernel
這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
- 初始化 FlutterView,開始載入 bundle
- 初始化Flutter Bundle,這裡獲取了 Flutter 的入口方法、Flutter 的 library, 以及對 Flutter 入口方法的呼叫。
初始化的邏輯比較複雜,對後續一些初始化相關的效能優化應該也會有不小的啟發。FlutterMain
中對資源的處理和寫入本地的邏輯也給 Android 端研究 Flutter 動態化提供了基礎。
很多 bundle 載入和後續初始化的邏輯也還沒有完全弄清楚和深入研究。有興趣的朋友可以一起研究,共同探討。