1. 包体积的组成
APK分析内容物可以得出:
vbnet
lib,Flutter端的代码实现以及依赖库。
- assets,Flutter端使用到的资源文件。
- dex,原生端的代码实现以及依赖库。
- res,原生端使用到的资源文件。
针对 Flutter 包体积给大家讲讲 Flutter 包体积现状,以及它由哪几个部分组成。
Android侧的Flutter产物总共5.16MB,由四部分组成
无论是Android还是iOS,Flutter的产物大体可以分为三部分:
- Flutter引擎,该部分大小固定不变,但初始占比较高。
- Flutter业务与框架,该部分大小随着Flutter业务代码的增多而逐渐增加。它是这样的一个曲线:初始增长速度极快,随着代码增多,增长速度逐渐减缓,最终趋近线性增长。原因是Flutter有一个Tree Shaking机制,从Main方法开始,逐级引用,最终没有被引用的代码,比如类和函数都会被裁剪掉。一开始引入Flutter之后随便写一个业务,就会大量用到Flutter/Dart SDK代码,这样初期Flutter包体积极速增加,但是过了一个临界点,用户包体积的增加就基本取决于Flutter业务代码增量,不会增长得太快。
- Flutter资源,该部分初始占比较小,后期增长主要取决于用到的本地图片资源的多少,增长趋势与资源多少成正比。
2. 优化方案
包体积的优化无非是三个方式:删、缩、挪
2.1.删减法
删就是移除无用代码和无用资源,删有可能是你人肉手动删,有可能是机器自动删,或者编译的时候删除,比如刚才的 Tree Shaking 机制就是编译时自动删除。
2.2.压缩法
当你删不动时可以想一下压缩,压缩典型的有压缩图片资源等。
2.3. 移除非必要产物,动态下发。
如果是已启动就要用的, 是不能动态下发的
基于动态下发的Flutter包大小优化方案 (重点)
它包括编译时和运行时两部分的操作:
- 工程配置:配置需要上传的so和assets文件。
- App打包时,会将配置1中的文件压缩上传到动态发布系统,并从APK中移除。
- App每次启动时,向动态发布系统发起请求,请求需要下载的压缩包,然后下载到本地并解压,如果本地已经存在了,则不进行下载。
总结: 动态下发:剥离 Data 段及一切非必要产物,打包后动态下发。
后续,我们还会探索Flutter的分包逻辑,通过将不同的业务模块拆分来降低单个产物包的大小,来进一步保障包瘦身功能的可用性。
具体操作:
完整的优化方案概括来说就是:动态下发+自定义引擎初始化+自定义资源加载
打包阶段:我们在原有的APK打包流程中,加入一些自定义的gradle plugin来对Flutter产物进行处理。在预处理流程,我们将一些无用的资源文件移除,然后将flutter_assets中的文件打包为bundle.zip。然后通过DynLoader提供的上传插件将libflutter.so、libapp.so和flutter_assets/bundle.zip从APK中移除,并上传到动态发布系统托管。其中对于多架构的so,我们通过在build.gradle中增加abiFilters进行过滤,只保留单架构的so。最终打包出来的APK即为瘦身后的APK。
动态加载后, 需要做的一些操作:
1.Flutter路由拦截
2.自定义引擎初始化
3.自定义资源加载
3. 优化 Engine 编译产物
编译的过程
👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀