【译】Flutter 延迟组件原理与自定义 【包体积优化 _ 动态化

dart 中 loadLibrary() 会调用的 native 层的 Dart_DeferredLoadHandler 函数,该回调函数在DartIsolate::Initialize 中由 Dart_SetDeferredLoadHandler 设置。Dart 在内部检索分配给库的加载单元 ID,并将其传递给回调函数。回调到 DartIsolate::OnDartLoadLibrary。

加载单元 ID 然后通过 runtime controller、engine 和 platform view 传递到 Android 嵌入层中的 FlutterJNI。这里,加载单元 ID 被传递到 DeferredComponentsManagerinstallDeferredComponent 方法中, ID 从一个整数映射为一个 String 名称,标识请求库所属的 pubspec 定义的延迟组件。这个转换由 AndroidManifest 中的 meta-data 映射,在构建阶段创建并验证。

之后 PlayStoreDeferredComponentManager 调用 API 下载 module。module 安装会定位到 .so 文件,并将路径传递给 engine 执行 dloopen。engine 将解析的符号发送到 dart isolate,以此将这些符号加载到 dart VM 中。整个加载过程必须与加载单元 ID 关联,否则 loadLibrary() 返回的 Future 对象不会完成。

请记住,多个加载单元可能包含在一个延迟组件中,但是 loadLibrary 只会从调用的特定 dart 库中加载 dart 符号。每个加载单元在使用前必须单独的调用 loadLibrary。对已经下载过的组件,后续调用 loadLibrary 不会二次加载,但是也并非同步完成,在调用和完成之间至少有一帧间隔。

通过延迟组件名称进行安装

我们还提供了 framework-side DeferredComponent utility class,它允许通过延迟组件名来直接安装。

这个方法可以有两个用途:

  • 安装只有静态资源的延迟组件。
  • 提前下载延迟组件以供以后使用。但是,为了使用提前下载组件中的 dart 代码,仍然必须调用loadLibrary() 。

这个直接的 API 通过 platform channels 直接调用 DynamicFeatureManagerinstallDeferredComponent 方法,并且由于未指定的加载单元,不会加载组件的任何 dart 代码。仅有静态资源被加载。要使用 dart 代码,还必须调用 loadLibrary()

卸载

DeferredComponent 的工具类中还提供了 uninstallDeferredComponent 方法,该方法使用 platform channels 请求操作系统卸载并删除与指定的延迟组件关联的文件。不同平台的卸载行为也不一样,在 Android 中文件的删除是排队的,在实际执行之前可能需要很长时间。

只能用将要卸载的组件名称来请求卸载。目前还不支持通过加载单元 id 或直接调用 dart 来卸载。

工具

延迟组件必须构建为 Android App Bundles (.aab) 才能正常工作。如果构建为调试文件或 apk 文件,则 dart 将正常编译并生成一个 .so 文件。

延迟组件使用 $ flutter build appbundle 命令构建,它会检查 pubspec.yaml 中是否存在 deferred-components: 来决定是否延迟构建。当应用程序中包含延迟组件并且构建模式为 profile 或者release,gen_snapshot 会收到一个 ——loading_unit_manifest 路径,它告诉 gen_snapshot 生成拆分的 AOT 产物,包含一个基本文件,以及一个 .so 用于代码库中的每个延迟库。这些分割的单元称为「加载单元」,并被分配一个内部整数 ID,称为加载单元 ID。

构建过程还依赖于项目设置来发挥作用。每个延迟组件必须对应于应用程序的 android 目录下定义的 android module。基本 module 被构建为 app ,而每个附加组件应该有一个与该组件同名的 module。基本模块AndroidManifest.xml 也需要包含加载单元 id 和延迟组件之间的映射。

flutter build appbundle 命令会执行一个验证程序,这个验证程序会指导开发人员完成正确的构建。验证程序是必要的,因为在 gen_snapshot 完成编译之前,无法知道 gen_snapshot 生成的加载单元。因此,某些项目设置只能 gen_snapshot 步骤之后才能完成。

因为错误地将延迟组件库作为非延迟组件库导入会导致文件被编译到基本加载单元中,所以延迟组件验证程序也有一种机制来防止对应用最终生成的加载单元的意外更改。如果生成的加载单元与缓存在 deferred_components_loading_units.yaml 文件中前一次运行的结果不匹配,则此检查将导致构建失败。在检测到由更改而抛出错误后,如果没有进行其他更改,构建将在下次运行时自动通过此检查。这意味着这个检查不是错误证明,因为你仍然可以忽略不匹配的加载单元错误,并继续构建。

自定义实现

可以不通过 Android Play 商店实现自定义下载。这只推荐给高级开发者,主要针对具有特殊需求的应用,如超大的静态资源,某些特定地下载行为,或无法访问 Play 商店的地区(如中国)。

简介

Flutter 嵌入层允许自定义实现,处理自定义的的延迟组件下载和解压,同时仍然允许访问核心的 Dart 回调,该回调将加载单元注册到 Dart runtime。这个过程比默认的 play store 版本要复杂。

要实现一个自定义延迟组件系统,主要包含以下部分:

  • DeferredComponentManagerAndroid 嵌入层的实现,用于处理应用程序和服务器之间的通信,并从下载的组件中提取 .so 文件和静态资源。

  • DeferredComponentManager 兼容的打包组件的工具,并解释加载单元的 gen_snapshot 输出。

  • 存放组件的服务器,如果没有 Play 商店作为动态功能模块下发,这就必须定制的。

下面的部分会做详细的指导:

DeferredComponentManager- 安卓嵌入层

嵌入层负责下载和安装打包的组件文件。这可以通过在 Android 嵌入层中继承抽象类 DeferredComponentManager 来实现

installDeferredComponent 是这个类的入口 ,它提供了加载单元 id 和组件名称,来确定要安装什么组件。loadLibrary() 的调用传递唯一的一个加载单元 id,而框架层中的DeferredComponent.installDeferredComponent() 的调用需要传入位移的组件名来加载只含静态资源的组件。

为了将加载单元 id 解析为特定的组件,通常需要存储加载单元 id 到组件名称的映射。在默认实现中,我们通过在应用程序中的 AndroidManifest.xml 中存储一个键值对数据来实现,但这可以以任何想要的方式实现。

你可以在 engine 源码中的 shell/platform/android/io/flutter/embedded /engine/deferredcomponents/DeferredComponentManager.java 中找到 DeferredComponentManager 每个方法的详细解释。默认的 Play store 实现可以在 shell/platform/android/io/flutter/ embedded /engine/deferredcomponents/PlayStoreDeferredComponentManager.java 中找到,可以作为一个粗略的实现指南。

要加载 Dart 库,请提供加载单元 id 和路径列表并调用 FlutterJNI.loadartdeferredlibrary 提供,这些路径包含你的 loadartlibrary 实现中的 .so 文件。engine 会尝试检索提供的每一个路径,直到文件被成功打开。

要加载新静态资源,创建一个可以访问新下载的静态资源的资源管理器。通过 FlutterJNI.updateJavaAssetManager 更新。

FlutterJNI 实例是通过 setJNI 传入。

工具

Flutter 的构建工具有引导 gen_snapshot 构建为拆分的 AOT 以及打包 .so 文件和静态资源到 Android 动态 module 的能力。自定义实现通常无法使用此工具。因此,您可能必须编写自定义工具来打包 .so 文件和静态资源,以便与自定义的 DeferredComponentManager 协同工作。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

学习福利

【Android 详细知识点思维脑图(技能树)】

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

详细整理在GitHub可以见;

Android架构视频+BAT面试专题PDF+学习笔记

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

t/topics/618156601)**

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

  • 26
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值