随着项目版本的迭代,功能不断丰富,app的体积也愈来愈大,动辄几十MB甚至上百MB,用户看到这么大的体积,相信如果不是版本强制更新,绝大多数用户对版本更新都会敬而远之吧。毕竟更新一次版本的成本也太大了,不说流量不够用,假如网络不好,更新的时间成本也是不可小觑的,这对于体量不是很大的业务线来说是灾难性的,用户的可以选择的替代品太多了,如何能够在如此激烈的竞争环境中脱颖而出呢,降低包大小,让用户高高兴兴的去下载去更新,这也是我们app开发者需要去好好思索的。
APK文件结构
既然要优化包大小,首先要了解apk的组成部分。APK 文件由一个 Zip 压缩文件组成,其中包含构成应用的所有文件。这些文件包括 Java 类文件、资源文件、签名文件等。
优化方案 优化目录 优化.arsc
.arsc中存在一个对应关系 关于文件,第一时间想到的就是压缩存储,在app运行时,要经常用到这个id,说明这个文件需要被频繁的读取。如果将这个文件进行压缩,在第一次读取之前必须进行解压的操作,就会有一些性能和内存的开销,综合考虑是得不偿失的。
具体可参见 //…
优化META-INF
.MF:是摘要文件,程序会遍历apk包中所有的文件,对非文件夹、非签名文件的文件,逐个编码生成摘要信息,并记录于此。如果逆向修改了任何文件,那么将出现文件和摘要信息不匹配的情况,导致安全校验失败。每一个资源文件都有一个sha1-的值,为该文件sha-1的值进行编码后的结果。
CERT.SF:是对.MF的签名文件,经过三步生成:
可以这样理解CERT.SF的作用:
CERT.RSA:包含了公钥和加密算法等信息,而最重要的信息是“对CERT.SF用私钥进行加密之后的值”。
META-INF文件夹下的文件环环相扣,总结如下:
优化建议:通过分析得出,除了RSA没有缩减机会外,其余两个文件都可以通过混淆资源名称的方式进行压缩。
优化Res目录
defaultConfig {
...
resConfig "zh"
}
这样配置后,打包时会排除私有项目、 库、三方库中的非中文资源文件。
目录允许下面有多级子目录,而Raw不允许存在字目录结构。目录不会产生R文件,Raw则相反因为Raw文件会产生R文件的映射,所以可以被lint分析,而不能Raw不支持子目录让其无法成为存放多种类文件的目录
Raw虽然不会对文件大小有限制,但是存放的音频文件尽量不要使用无损格式,可以考虑同等质量但文件更小的音频格式,如OGG、wav、mp3等格式
减少文件
减少有两个方法:复用和融合。
复用:把一些页面共用的布局抽出来,这对于文件的管理还是瘦身都非常有用。
融合:对于不会被复用的呢?
动态下载图片
贴纸、表情这类的文件是相当大的,对于这类图片资源,强烈建议通过在线的方式获取,虽然有一点的复杂度和出错率,但是投入产出比还是不错的。
分目录放置图片
不同分辨率的图片应该放在不同的目录中,如果放错了,对于app运行时的内存大小会有一定的影响。
如果把一个本来应该放在-里面的图片放在了文件夹中,会出现什么问题呢? 在设备上,图片会放大3倍,图片内存占用会变为原来的9倍。
因为不同分辨率的图片大小有差距,很多认为可以使用一套图片来做,不用多套图,借此达到瘦身的目的。但谷歌建议针对不同分辨率出不同的图片。 比较通用的做法是:
优化图片资源
图片的优化,最重要的是知道选择什么样的图片格式。
webp格式从4.0开始原生支持,知道4.2.1才支持显示含有透明度的webp,一般png转换为webp,大小可以减少一半
另外,在大型项目中,会引入汗多库以及三方库,如果库中包含一些大图,并且不会用到的话,可以用1x1的同名透明图片替代,达到技能编译通过,又能缩小体积的目的。
针对动画,尤其是帧动画,一直是相当占用资源的,现在可以使用svg动画或者公司的动画库实现,如果使用可以直接使用json文件描述动画,图片会减少很多。
优化dex
dex文件是class文件被编译后可供art虚拟机理解的文件格式,可以理解为java代码包。
利用lint分析无用代码
可以借助 Code,对工程做静态代码检查。Lint是一个强大的工具,它能做的事情不限于检查无用资源和代码,它能检测丢失的属性、写错的单位、会引起内存溢出的代码等,当然Lint虽然强大,但也会带来一些缺点,就是生成的信息量过大,不适合快速定位无用的代码。除此之外,Lint会提示不要使用枚举方法,如果将枚举变为int,apk的大小也会缩小一些,没减少一个enum,可以减少大约1到4kb的大小。
删除R文件
中的R文件,除了类型外,所有的字段都是int型变量或者常量,且在运行期间都不会改变。可以在编译时记录R中所有字段的名称以及对应值,然后利用ASM工具遍历所有class,将引用R字段的地方替换成对应的常量 插件可以方便地将R.xxx的地方替换为具体值,可以减少一部分dex大小。
在最外层的build.中加入如下依赖:
classpath 'com.mogujie.gradle:ThinRPlugin:0.0.2'
在内层的文件中加入如下代码:
apply plugin: 'thinR'
thinR {
//为了不影响日常开发的编译速度,debug版本可以不用删除R
skipThinRDebug = true
}
启用:
是一款优秀的代码优化、混淆工具,适用于java和。关于,最需要了解的是它的方法检测机制。它将产出的class作为输入,然后寻找代码中所有的调用点,计算出代码中可达的调用关系图,然后移出剩余的部分,将真正用到的方法变量保留下来进行优化,最终输出一个新的class。
上图简单描述了什么是可达和不可达的代码
buildTypes {
release {
minifyEnabled true
shrinkResources true //压缩资源
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
虽然这种方式成果显著,但也要配合正确的规则才能起作用。
这张图展示了原始apk和混淆后apk的大小差异
每次构建时,都会输出下列文件:
利用混淆来删除代码的方式是一种保险措施,真正治本的方法是在开发过程中随手删除无用的代码。
结语
控制app的大小非常重要,但也不是一蹴而就的,这是一个持续性的过程,也许隔几个月或者隔几个版本,就需要我们去检查一下大小是否有了足够多的冗余,在开发过程中,及时删除废弃的资源文件和代码也是一个良好的习惯。
最后,保持好的开发习惯,砍掉不必要的功能才是保证包体积持续优化的超级大招,这里再给大家分享一份《性能分析与优化实战进阶手册》,如有需要参考的可以 私信回复 666 即可货取!!!
42岁郝蕾,3个月瘦35斤,3个“懒人减肥技巧”,简单、实用,郝蕾,减肥,瘦身,减肥方法,瘦腰,瘦腿
记者 | 张倩楠 编辑 | 翟瑞民1 国家发改委日前正式发布《“十四五”新型城镇...
去年听同事说麦吉减肥法见效特别快,所以试了下,瘦了18斤,开开心心吃了一年,今年又开始了,分享给大家,也防止自己丢失。 麦吉减肥法一、科学原理 当饮...
不得不说李佳琦绝对有些玄学在身上,在我犹豫要不要用白芸豆减肥的时候,网上已经有他推荐的那个白芸豆传说了! 经过我2个月的使用,得出结论:这个白芸...
让上海公交25路女司机蔡筱瑾没想到的是,开了28年“辫子车”的她,竟然在临退休前的一个多月,没有了车顶上的“牵绊”。_新浪网...