深入解析 Flutter 初始化流程
在调研 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 动态化提供了基础。
有需要Android进阶全面系统视频资料的可以加入Android进阶交流群;701740775。免费获取 加群请备注csdn领取进阶资料

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
如何简单快速搭建 Android 大仓
书接上文,上回提到 B 站Android团队为了解决组件化后协作上的问题,已经采用了大仓(monorepo)的方案来组织代码。 国内实践大仓的团队少之又少,更别提 Android 的大仓了,几乎没有来自其它团队的可借鉴经验。在这条路上,我们可以算作先行者。本文粗陋,文中所列思路不可能适用所有团队,仅给同样想实践Android 大仓的人些许启发。 一个标准的 Gradle 项目 首先回顾一下 Android 项目的组织方式。自从13年开始官方逐渐迁移到Android Studio做为 IDE 后,Android 项目的开发和编译就绑在 Gradle上了。 一个标准的 Gradle 项目结构如下所示: MyApp/ ├── build.gradle ├── settings.gradle ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradle.properties └── app ├── build.gradle └── src └── ...
- 下一篇
Mac 中下载阅读 Android 源码
准备工作:创建区分大小写的 APFS 宗卷 国内使用 Android Source 官方的下载方式有点慢,所以通常建议使用国内的 AOSP 镜像,一般是中科大的镜像或者清华大学的镜像,本文使用的是清华大学的镜像。 先下载 repo 工具: PATH=~/bin:$PATH curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo chmod a+x ~/bin/repo 然后有两种下载方式,分别适合不同场景。 1.1 下载最新版本的源码 如果需要下载最新版本的源码,建议使用镜像中的每月初始化包。先下载初始化包,其中包含了.repo目录,然后解压再repo sync一次就完成了。 推荐使用 axel 工具下载,速度快,支持断点续传。 axel -n 3 https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-latest.tar # 解压得到 aosp 目录 tar xvf aosp-latest.tar cd aosp # 同步一次 rep...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8安装Docker,最新的服务器搭配容器使用
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7设置SWAP分区,小内存服务器的救世主