深入解析 Flutter 初始化流程

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 在调研 Flutter 动态化方案的时候,需要了解 Flutter 加载 dart 产物的流程,于是梳理了一遍 FLutter 的初始化流程flutter的源码下载地址在 github 上可以找到,具体地址: gith...

在调研 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 的初始化流程就就简单的分析了一遍。大致可以总结成三个部分

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

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

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

相关文章
|
10天前
|
开发工具
Flutter-AnimatedWidget组件源码解析
Flutter-AnimatedWidget组件源码解析
手机上网流程解析
【9月更文挑战第5天】
|
24天前
|
测试技术 持续交付 UED
|
20天前
|
持续交付 jenkins Devops
WPF与DevOps的完美邂逅:从Jenkins配置到自动化部署,全流程解析持续集成与持续交付的最佳实践
【8月更文挑战第31天】WPF与DevOps的结合开启了软件生命周期管理的新篇章。通过Jenkins等CI/CD工具,实现从代码提交到自动构建、测试及部署的全流程自动化。本文详细介绍了如何配置Jenkins来管理WPF项目的构建任务,确保每次代码提交都能触发自动化流程,提升开发效率和代码质量。这一方法不仅简化了开发流程,还加强了团队协作,是WPF开发者拥抱DevOps文化的理想指南。
39 1
|
25天前
|
缓存 运维 Linux
深入解析:一步步掌握 CentOS 7 安装全流程及运维实战技巧
深入解析:一步步掌握 CentOS 7 安装全流程及运维实战技巧
|
11天前
|
缓存 网络协议 Linux
DNS的执行流程是什么?
DNS的执行流程是什么?
24 0
|
20天前
|
持续交付 jenkins C#
“WPF与DevOps深度融合:从Jenkins配置到自动化部署全流程解析,助你实现持续集成与持续交付的无缝衔接”
【8月更文挑战第31天】本文详细介绍如何在Windows Presentation Foundation(WPF)项目中应用DevOps实践,实现自动化部署与持续集成。通过具体代码示例和步骤指导,介绍选择Jenkins作为CI/CD工具,结合Git进行源码管理,配置构建任务、触发器、环境、构建步骤、测试及部署等环节,显著提升开发效率和代码质量。
37 0
|
20天前
|
C# 开发者 Windows
震撼发布:全面解析WPF中的打印功能——从基础设置到高级定制,带你一步步实现直接打印文档的完整流程,让你的WPF应用程序瞬间升级,掌握这一技能,轻松应对各种打印需求,彻底告别打印难题!
【8月更文挑战第31天】打印功能在许多WPF应用中不可或缺,尤其在需要生成纸质文档时。WPF提供了强大的打印支持,通过`PrintDialog`等类简化了打印集成。本文将详细介绍如何在WPF应用中实现直接打印文档的功能,并通过具体示例代码展示其实现过程。
79 0
|
20天前
|
监控 测试技术 API
|
20天前
|
开发者 监控 开发工具
如何将JSF应用送上云端?揭秘在Google Cloud Platform上部署JSF应用的神秘步骤
【8月更文挑战第31天】本文详细介绍如何在Google Cloud Platform (GCP) 上部署JavaServer Faces (JSF) 应用。首先,确保已准备好JSF应用并通过Maven构建WAR包。接着,使用Google Cloud SDK登录并配置GCP环境。然后,创建`app.yaml`文件以配置Google App Engine,并使用`gcloud app deploy`命令完成部署。最后,通过`gcloud app browse`访问应用,并利用GCP的监控和日志服务进行管理和故障排查。整个过程简单高效,帮助开发者轻松部署和管理JSF应用。
32 0

热门文章

最新文章

推荐镜像

更多