美文网首页
包体积优化实践记录

包体积优化实践记录

作者: Johnson_Coding | 来源:发表于2023-05-01 13:40 被阅读0次

背景

前段时间我们项目开发工作完成后对项目进行一些优化工作,众所周知 , 性能优化是个持久长期的过程,纬度很多,包括启动、卡顿、内存、网络、电量等等,个人认为包体积优化投入产出比是最高的,流程简单,时间花销很少,但能带来体积大幅度缩减直观收益,而且具有通用型,能给每个项目优化提供参考。上周应用市场对接支付宝小程序和智能场景卡片,需要车机预装引擎包,邢捕头透露目前A1上提供的DC系统分区空间已经不足了,所以包体积优化应当引起重视。

优化前:11.9M

APK组成

文件描述

libjar,aar,so文件,不同的cpu架构

res编译后的资源文件,drawable、layout等

assets应用程序的资源、字体、音频文件等

classes(n).dexdx编译后的java文件

META-INF签名信息相关

resources.arsc二进制资源的映射信息,根据R文件找到对应资源

kotlin编译后的kotlin文件

AndroidManifest.xml清单文件

APK构建流程

优化思路

APK本质是一个压缩文件,是打包后的产物,那可以作为切入点的阶段就是打包前、打包中。

打包前,即减少打包的文件,比如无用的资源、代码;

打包中,对打包中的产物进行混淆压缩,比如资源文件、So文件;

基本操作

1、Lint检测无用资源文件

Analyze > Run Inspection by Name > Unused resources

//由于项目没有多余资源,提示如下:(如果有的话,确定无用删除即可)

注意: 因为lint是本地静态扫描,所以动态引用的资源文件并不会识别出来,也会出现在检测列表里。

2、Lint检测无用代码

因为本人电脑安装了alibaba java coding guideline,检测结果包含Lint检测代码。

注意: 因为lint是本地静态扫描,所以反射、动态引用的class并不会识别出来,也会出现在检测列表里。

lint优化后大小:11.9M →11.8M

3、图片压缩

推荐使用tinypng在线压缩。

原理: TinyPNG的压缩是通过减少颜色数量,将24-bit的图像文件转换成8-bit,来大幅度缩小图片体积。(有损,肉眼不可见)

4、TinyPngPlugin

手动压缩毕竟不高效,可以使用TinyPngPlugin一键压缩。plugins搜索TinyPng安装即可。(新版AS安装完plugin已经不需要重启了)

压缩结果:

    3张图片,可以看到效果还是非常可观的。如果图片多,效果更加明显。

5、图片转WebP

那这3张图还能继续优化吗?可以,WebP格式的体积更小,而且AS也提供了一键转换支持,但经过TinyPNG压缩后的体积转为WebP格式不一定每次都会更小。

以load_empty.png为例:

load_empty.png优化后原始大小9KB经过TinyPng压缩再经WebP格式转换缩小为3.82K

可以看到,较原始大小减少了68%

注:尝试对task-lib的png图片进行压缩,提示9-Patch图无法converted webP

优化后大小为:11.9M →11.8M→ 8.8M

6、R8编译优化

R8采用D8 + ProGuard的形式构建,将Proguard(混淆、压缩、优化)和D8(Java字节码转化成dex代码,编译优化体积优化)工具进行整合,目的是加速构建时间和减少输出apk的大小。

                                      -D8编译过程-

                                              -R8编译过程-

desugaring脱糖、shrinking压缩、obfuscating混淆、optimizing优化、 dexing编译一步到位

开启R8的好处:

代码缩减(摇树优化):使用静态代码分析来查找和删除无法访问的代码和未实例化的类型,对规避65535 引用限制非常有用;

资源缩减:移除不使用的资源,包括应用库依赖项中不使用的资源。

混淆代码:缩短类和成员的名称,从而减小 DEX 文件的大小

优化代码:检查并重写代码,选择性内联,移除未使用的参数和类合并来优化代码大小

减少调试信息 : 规范化调试信息并压缩行号信息。

//AS版本升级到3.4以上

minifyEnabled true //启用R8代码缩减功能。

shrinkResource true //启用R8资源缩减功能

注:R8包含混淆,如果不想混淆的代码和资源需要配合自定义混淆规则使用

优化后体积缩减:11.9M →11.8M→ 8.8M→6.7M

7、zipalign启动优化

zipalign 是 Android 提供的一个整理优化 apk 文件的工具,原理大概是格式化Zip文件夹的二进制文件的序列进行优化重排,达到提升系统解析速度。提高系统和应用的运行效率,更快地读写 apk 中的资源,降低内存的使用。所以对于要发布的 APP,在发布之前一般要使用 zipalign 进行优化。

zipAlignEnabled true //启动优化

8、so文件缩减

android studio默认会打包成4种架构,ZEEKR车机端不管是A1还是BX1E都是arm64架构的,所以保留arm64-v8a一种即可,其他直接删除。

由于之前应用市场已经优化过此问题,如果还原发现,lib文件从166KB增大为667KB

只保留一种架构需要设置:

9、移除未使用的备用资源

很多出海的应用会做国际化,但也适配不了这么多的语言。除了自己app的之外,还有一些官方的、三方的,可以统一配置支持的语言。

应用市场没有做海外语音适配 & 从一开始就只有xhdpi一种分辨率

defaultConfig {

//三种语言   

resConfigs("en","zh","zh-rCN")

}

资源文件同理,如果不进行唯一标识,默认会打包生成mdpi、xhdpi、xxhdpi3种

defaultConfig { "zh",resConfigs("xhdpi") }

10、小结

针对上面的基本操作做个小结,看看目前效果如何。

11.9M →11.8M→ 8.8M→6.7M 包体积减少43%,事实上应用市场自身特性也决定了对网络依赖性很强,本地资源很少,很多车机项目包体积减少效果会更大。

高阶操作

1、功能重复的三方库整合

1、比如glide和picasso,都是图片库,保留其一即可。

2、同一个三方库的不同版本。

File-Project Structure 查询依赖关系

3、其他一些特定业务操作。

2、so动态加载

├── armeabi-v7a/

│ ├── libmmkv.so

├── arm64-v8a/

│ ├── libmmkv.so

├── x86/

│ ├── libmmkv.so

└── x86_64/

├── libmmkv.so

很多三方库依赖的so文件占比比较大,而且由于适配不同架构包含多种一样的so文件,可以考虑so文件做按需远程下载&动态下发。也就是插件化的思想。

可以看出正常安装APK时:

PackageManagerService根据当前设备架构拷贝对应So文件到/data/app_libs/

启动APP,framework创建应用的ClassLoader实例,并将所有so文件所在目录注入 ClassLoader 字段中

调用 System#loadLibrary("xxx.so") , Framework从当前上下文classLoader的目录数组里查找so

native通过dlopen函数加载so

调用JNI方法

我们要做的就是把自定义的native库path插入nativeLibraryDirectories最前面,即使安装包libs目录里面有同名的so,也优先加载指定路径的外部so。

/** 例如Tinker源码中sdk25版本动态加载so的方案

https://github.com/Tencent/tinker/blob/ec6f1f5471d40d9e5c2386a25f468eb112c3aa86/tinker-android/tinker-android-lib/src/main/java/com/tencent/tinker/lib/library/TinkerLoadLibrary.java

*/

private static void install(ClassLoader classLoader, File folder) throws Throwable {

// step1: 反射获取 pathList

final Field pathListField = ShareReflectUtil.findField(classLoader, "pathList");

final Object dexPathList = pathListField.get(classLoader);

// step2: 拿到nativeLibraryDirectories

final Field nativeLibraryDirectories = ShareReflectUtil.findField(dexPathList, "nativeLibraryDirectories");

List<File> origLibDirs = (List<File>) nativeLibraryDirectories.get(dexPathList);

// step3: 如果 origLibDirs 内已有我们的路径了,移除掉

...

// step4: 将我们的路径放在集合首位,这样会优先加载,实现so的替换

origLibDirs.add(0, folder);

// step5: 获取 pathList 系统路径集合

final Field systemNativeLibraryDirectories = ShareReflectUtil.findField(dexPathList, "systemNativeLibraryDirectories");

List<File> origSystemLibDirs = (List<File>) systemNativeLibraryDirectories.get(dexPathList);

// step6: addAll 两者所有路径

final List<File> newLibDirs = new ArrayList<>(origLibDirs.size() + origSystemLibDirs.size() + 1);

newLibDirs.addAll(origLibDirs);

newLibDirs.addAll(origSystemLibDirs);

// step7: 生成一个新的 natieLibraryPathElements 集合

final Method makeElements = ShareReflectUtil.findMethod(dexPathList, "makePathElements", List.class);

final Object[] elements = (Object[]) makeElements.invoke(dexPathList, newLibDirs);

// step8: 覆盖掉原有的路径集合

final Field nativeLibraryPathElements = ShareReflectUtil.findField(dexPathList, "nativeLibraryPathElements");

nativeLibraryPathElements.set(dexPathList, elements);

}

收益很大的同时,风险也很大,有很多case需要考虑到,比如下载时机、网络环境、线程进程,尤其是so库文件之间有依赖关系时有很多问题需解决。

可以参考facebook开源的SoLoader。

3、插件化

宿主APP按需动态下发多个子apk。

腾讯Shadow-零反射全动态Android插件框架

任何软件工程遇到的问题都可以通过增加一个中间层来解决

其他方案

1、原生改用H5或小程序等方案

有些功能可能原生做就显得太重,比如各种促销活动,需要加载各种大图,原生既重又不够动态化,这个时候H5是一种很好的替代方案。但是如果你原本就不支持H5或者小程序的话,接入这种能力可能反而会加大包体积,做好对比。

2、砍功能

有些功能可能想的很美好,但上线之后收益并不大,是否需要重新思考价值点,最好找到数据依托,再跟产品打架。

3、修改三方库的源码,不需要的代码剔除

比如引入了一个功能很齐全的三方库utils,但实际只用到几个,对源码进行抽取也能减少包体积,同时还能减少网络下载的编译时间。弊端就是升级成本较大。

4、图片网络化

即把图片上传到服务器,通过动态下载的方式减少包体积,弊端就是首次加载的时候依赖网络环境,对加载速度、流量需要做一个平衡。图片可以预加载,但是流量消耗是无法避免了,如果比较在意流量指标,需要权衡了。

包体积监控

包体积监控应该作为发布流程的一个环节,最好是做到流程化,否则很难持续,没几个版本包体积又涨上来了。大致思想:当前版本与上一个版本的包大小做对比,尽可能不做依赖、大小超过2M需要审批并给出原因和后续优化方案等等。

Matrix Android ApkChecker · Tencent/matrix Wiki · GitHub(Matrix是微信终端自研和正在使用的一套APM(Application Performance Management)系统。 Matrix-ApkChecker 作为Matrix系统的一部分,是针对android安装包的分析检测工具,根据一系列设定好的规则检测apk是否存在特定的问题,并输出较为详细的检测结果报告,用于分析排查问题以及版本追踪。Matrix-ApkChecker以一个jar包的形式提供使用,通过命令行执行 java -jar ApkChecker.jar 即可运行。)

相关文章

  • iOS安装包瘦身

    记录一次安装包大小优化的实践。维持安装包体积是一个持续的过程,建立预警机制,监控每个版本的体积大小。 资源文件优化...

  • 包体积优化-实践

    最新公司业务线一个App尝试切换到androidx后,与上期版本相比包大小突然从19.9增加了9M的地址,对照着官...

  • 包体积优化

    为什么需要优化包体积 下载转化率,包体积增加不利于用户下载 推广成本,包体积增大推广成本也会加大 应用市场限制 包...

  • 包体积优化

    1.删除无用图片资源https://github.com/tinymind/LSUnusedResources2....

  • 包体积优化

    Aandroid的安装包APK文件本身就是个压缩文件,把后缀改成.zip,解压后,能看到安装包的内容包括 要减少安...

  • 包体积优化

    https://juejin.cn/post/7116089040264232967[https://juejin...

  • Mac上提取assets.car图片

    我们在进行包体积优化时,会去查看分析ipa包,因为看到这篇文章iOS 优化IPA包体积(今日头条)[https:/...

  • 包体积瘦身

    包体积是什么 包体积优化前,先要明白包体积是什么,在app store上看到的体积又是什么。在app store里...

  • iOS性能优化

    1、参考文章 TableView优化 FPS监测 //启动优化、内存优化、卡顿优化、线程优化、电量优化、包体积...

  • Android 可能你想要的APK瘦身笔记

    导读:这是在今年项目体积优化时,记录的一些实战笔记,文中主要针对APK的包内容优化.其中优化手段主要有:字节码,资...

网友评论

      本文标题:包体积优化实践记录

      本文链接:https://www.haomeiwen.com/subject/nrmjzrtx.html