深入解析 Flutter 初始化流程

作者 : 开心源码 本文共3714个字,预计阅读时间需要10分钟 发布时间: 2022-05-12 共187人阅读

在调研 Flutter 动态化方案的时候,需要理解 Flutter 加载 dart 产物的流程,于是梳理了一遍 FLutter 的初始化流程

flutter的源码下载地址在 github 上可以找到,具体地址: github-flutter/engine

FLutterMain的初始化

先从 Android 的入口开始看

FlutterAppliationonCreate 中调用了

FlutterMain.startInitialization(this);

跟进去我们会看到调用了 startInitialization 方法,最后会顺序调用这几个方法

initConfig(applicationContext);initAot(applicationContext);initResources(applicationContext);

我们查看 initResources 方法如图

这里我们可以看到实际加载了assets里面的flutter资源。并且会把资源 copy 到本地的?路径。这里不做深究。 FlutterMan 的初始化基本包括了

  • 初始化配置
  • 初始化 AOT 编译
  • 初始化资源

3 个部分

继续看 ? FlutterView 的初始化:

FLutterView的初始化

FlutterActivity 为例,在 onCreate 中会调用到 FlutterActivityDelegate 的对应方法,最终调用 FlutterViewrunFromBundle 方法

public void runFromBundle(FlutterRunArguments args) {    this.assertAttached();    this.preRun();    this.mNativeView.runFromBundle(args);    this.postRun();}

跟踪这段代码,会调用 FlutterNativeViewnativeRunBundleAndSnapshotFromLibrary 方法。

这里会继续进行 ? 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_HOLDERLaunch 函数.

最终走到 engineRun 函数。

这里有 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 的入口方法。而 RunRunFromLibrary 的区别,则是假如我们传入了 entrypoint 参数去进行 Flutter 的 bundle 初始化的时候,则会去加载我们制定的 library。

小结

到这里, Flutter 的初始化流程就就简单的分析了一遍。大致可以总结成三个部分

  1. 初始化 FlutterMain
  2. 初始化 FlutterView,开始加载 bundle
  3. 初始化Flutter Bundle,这里获取了 Flutter 的入口方法、Flutter 的 library, 以及对 Flutter 入口方法的调用。

初始化的逻辑比较复杂,对后续少量初始化相关的性能优化应该也会有不小的启发。 FlutterMain 中对资源的解决和写入本地的逻辑也给 Android 端研究 Flutter 动态化提供了基础。

有需要Android进阶全面系统视频资料的可以加入Android进阶交流群;701740775。免费获取 加群请备注简书领取进阶资料

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 深入解析 Flutter 初始化流程

发表回复