IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【译】Flutter 延迟组件原理与自定义 【包体积优化 _ 动态化 -> 正文阅读

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

延迟组件主要通过 dart 中的 loadLibrary() 调用来触发被下载、安装和加载。这个调用在 dart2js 和 aot/native 中的处理是不同的。这里,我们梳理 loadLibrary() 调用转换为一个延迟组件的安装过程:

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/a![](https://www.hualigs.cn/image/61dba891ed8ee.jpg) ndroid/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 协同工作。

要让 gen_snapshot 生成加载单元和 .so 共享库,请将 ——loading_unit_manifest=<manifestPath> 配置传递给 gen_snapshot。他会在你的 manifestPath 中创建一个 .json 文件,包含加载单元和相应生成的 .so 库。之后,可以将 so 文件和静态打包成您希望在文件服务器上发布的任何格式。你还需要在 DeferredComponentManager 实现类中解析文件。

文件服务器

由于自定义实现通常不使用 Play 商店,用户应该实现一个文件管理服务。这部分的实现方式是很灵活的,唯一的要求是它能与 DeferredComponentManager 实现协同工作,以传输加载 Dart 共享库和静态资源所需的文件。

最后

其实根据 Gallery 的案例,我们可以看出,如果安装包中静态资源占比很高时,延迟加载对于 app 体积优化非常明显。而国内必须要通过自定义的方式实现延迟组件的管理,这本身是有成本的。所以,这项技术是否真正适合落地于业务中还需要评估收益比。但从技术本身的角度来看,里面可玩性还挺高的,提供动态加载库的能力其实可以发散很多方向。后面有空也尝试实践落地,如果你也感兴趣欢迎关注,点赞,在评论区留下你的看法。
列表流畅度优化分帧组件即将走完审核流程,预计两周内完成发布,欢迎关注我的动态。
往期优质专栏:
有空也尝试实践落地,如果你也感兴趣欢迎关注,点赞,在评论区留下你的看法。
列表流畅度优化分帧组件即将走完审核流程,预计两周内完成发布,欢迎关注我的动态。
往期优质专栏:

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-01-30 19:02:44  更:2022-01-30 19:03:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:43:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码