【Android】apk瘦身技术分享

背景

随着业务迭代,apk体积逐渐变大。项目中积累的无用资源,未压缩的图片资源等,都为apk带来了不必要的体积增加。调研了一些apk瘦身的方法后,总结如下。


可用方法

1.删除无用资源 

2.删除无用方法 

3.混淆(方法混淆&资源混淆 

4.使用一套图片资源 

5.图片压缩/其他图片格式 

6.so兼容一个平台,动态下载

7.精简第三方库


删除无用资源

1⃣️开启ShrinkResource

在build.gradle中配置shrinkResource=true

首先介绍一下shrinkResource的原理:在打包过程中会多出一个task,通过调用一个analyze方法进行无用资源的分析并进行处理,具体过程

1)根据R文件生成资源表,然后遍历所有的class文件,分析class中使用的资源,标记可达。

2)分析Manifest res,分析资源文件引用的其他资源,标记可达。

3)调用keepPossiblyReferencedResources,标记可能到达的资源。比如通过getIdentifier动态获取的资源⬇以下代码会将所有带有img_前缀的资源标记为已使用。

                   String name = String.format("img_%1d", angle + 1);

                   res = getResources().getIdentifier(name, "drawable", getPackageName());

(如果想开启严格检测,不标记可能到达的资源,在keep.xml配置 tools:shrinkMode="strict",对于不进行严格检测的资源,配置tools:keep 风险:开启严格检测可能导致程序有bao

⚠️然而,经过实验发现,开启shrinkResource并没有使apk变小。因为在打包时,无用资源并没有直接被清理,而是把部分无用资源用更小的东西代替掉。


2⃣️开启Lint检测

在Android Studio中 Analyze-Run Inspection by Name-unused resource(过程与ShrinkResource类似)

注意下图不要打勾,无效的id对apk体积增加微乎其微,删去却可能引起bug,得不偿失。



还有一种要注意的情况

例如 <String name="xxx"><font size="16">请输入用户名</font></String>

其中font size="16" 会被判定为无效资源,但是lint直接清除时,会把font标签内的内容全部删除,清理后的效果

<String name="xxx"></String>(文字丢失了,lint暂时还不够智能,但这种情况比较少见,review的时候仔细检查一下)

⚠️lint的检测可能存在遗漏,如第一次找到100个无用资源,删除后第二次查找后,可能还存在几个无用资源,可以多查几次


3⃣️删除无用的语言资源

在语言的配置上,只保留需要用到的语言,目前项目只保留中文即可,有些项目可能保留英文

defaultConfig{

        resConfigs "zh"

}


删除无用方法

1⃣️开启minifyEnabled

实验发现,开启后方法数从13w缩减到10w,效果还是比较显著的


2⃣️使用Lint查找无用符号并删除

Analyze——Run Inspection by Name——unused symbol(Kotlin)

Analyze——Run Inspection by Name——unused declaration (Java)

批量删除的时候会一直提问是否safe delete

开启了minifyEnabled后无用声明等基本不会增加apk的大小


3⃣️内部类访问宿主类中的private成员时,编译的时候会自动生成acces$方法,这种情况会导致方法数增多,如果

修改为非private权限就可以去除这个access$方法。(西瓜视频减少了5w左右的方法数,视不同项目决定)


4⃣️java语言中,考虑一些变量修饰符改为非private修饰,可以减少一些set和get方法


类/方法混淆

1⃣️配置proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro',此处采用默认的混淆文本,也可以自定义。使用keep保持不需要进行混淆的文件。

2⃣️配置优化的proguard: proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' (不太稳定,比如在Dalvik模拟器上可能发生闪退,不推荐)


资源混淆

AndResGuard是微信推出的一款开源工具,对资源文件进行混淆,使用的方法很简单,效果显著。

使用方法:https://github.com/shwenzhang/AndResGuard


原理:用更短的名字替换原来的长名字

res/mipmap/icon.png                       资源混淆后                 r/a/b.png

res/drawable/icon.png                ============>          r/c/b.png

res/drawable/splash.png                                                     r/c/d.png

(同一文件夹被映射到相同的新路径,同样的名字被映射到相同的资源名字)


⚠️白名单:若想通过getIdentifier方式获得资源,需要放置白名单中,否则找不到对应资源。务必将程序桌面icon加入白名单,友盟等,加入白名单。多测试,多测试,多测试!




更多原理可以参考:
https://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=208135658&idx=1&sn=ac9bd6b4927e9e82f9fa14e396183a8f#rd
https://wiki.bytedance.net/pages/viewpage.action?pageId=115947182


使用一套图片资源

除了桌面icon外,其他图片资源考虑只适配一种分辨率的,如只保留xhdpi目录下的资源图


图片压缩

使用tinypng进行图片压缩,可以反复压缩,但是相应解压缩时间变长,带来一些性能影响,对用户体验不会造成影响。

⚠️启动页图片最好不要进行压缩,启动时间会变长


tinypng批量处理

1)安装pip https://pypi.org/project/pip/

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py

sudo python get-pip.py

2)安装tinify

sudo pip install --upgrade tinify

3)生成tinypng key 每个月免费500张


对图片进行批量压缩,文件夹大小由1.5M减少到800+k,但是apk的大小实际减少300k左右。因为在打包过程中,本身就会对图片进行一定程度的压缩。

此外,谷歌开发了一款开源工具butteraugli,对压缩质量进行衡量 https://github.com/google/butteraugli


其他图片格式

1⃣️jpg 对于启动图等很大的图片,可以考虑用jpg格式代替png

2⃣️webp格式

支持4.0+设备,4.0以下不显示图片

在4.0 ~ 4.2.1的设备上无法显示带有透明度的webp,比如,把png转成webp则无法显示,但是如果把png先转成jpg再转成webp则能正常显示了,但会丢失透明度。

3⃣️矢量图svg

优点:矢量图由点和线组成,放再大也可以保持清晰度,占用空间小,不会出现锯齿

缺点:只支持5.0+系统,与位图相比多一层计算,消耗更多性能

⚠️android系统对png图片的解析时间是最短的,更换图片格式的时候要考虑一下性能损失。


so兼容一个平台

如删除armable-v7包下的so,基本上armable的so也是兼容armable-v7的,armable-v7a的库会对图形渲染方面有很大的改进,如果没有这方面的要求,可以精简。

⚠️不排除有极少数设备会Crash,充分测试,充分测试,充分测试。


精简第三方库

如果第三方库做了拆分,只引用需要的模块,不要引入整个库

如support-v4在24.2.0以后,做了拆分



总结

可以长期使用的方法总结如下

1⃣️2-3版本使用lint清除一次无用资源

2⃣️配置minifyEnable,开启类混淆

3⃣️对新加入的图,使用tinypng或其他工具进行压缩

4⃣️微信资源压缩工具AndResGuard,配置一次,永久生效(注意白名单,注意多测试

猜你喜欢

转载自blog.csdn.net/crab0314/article/details/80959448