目录
1. 为什么?
APK越大,在下载安装过程中,耗费的流量会越多,安装等待的时间也会越长,安装包的大小对下载的失败率也有影响。而对于应用本身,就意味着下载转化率会越低,在竞品中,用户更愿意选择功能多,体验号,安装包最小的应用。因此apk的瘦身优化也很重要。
2. 包体分析
在Android Studio工具栏里,打开build–>Analyze APK, 选择要分析的APK包
- res 主要存放图片资源
- lib 主要存放so库,各个cpu架构
- classes.dex是java源码编译后生成的java字节码文件,因方法限制拆分了多个dex
- assets 存放不需要编译处理的文件
- resources.arsc是编译后的二进制资源文件,包括图片,文本索引等
- META-INF 签名信息
- AndroidManifest.xml 描述配置文件
可以看到占用空间的主要是代码、图片、资源和lib以及assert文件。
瘦身的主要方向:精简代码、压缩图片、去除无用库、减少asserts文件(或大小)。
3. 常用方案
3.1混淆代码
代码混淆 ProGuard是一个开源的Java代码混淆器(obfuscation),并且默认集成到Android SDK中,它具有以下功能:
- 压缩:移除无效的类、属性、方法等。
- 优化:移除没用的结构。
- 混淆:把类名、属性名、方法名替换为一到两个字母。
ProGuard常用参数 ProGuard配置参数非常多,以下列出一些常用的参数,具体的参数可参考可参考ProGuard manual。
- 1. ProGuard配置
- -include {filename}:从给定的文件中读取配置参数。
- -basedirectory {directoryname}:指定基础目录为以后对应的档案名称。
- -injars {class_path}:指定要处理的应用程序jar、war、ear和目录。
- -outjars {class_path}:指定处理完后要输出的jar、war、ear和目录的名称。
- -libraryjars {classpath}:指定要处理的应用程序jar、war、ear和目录所需的程序库文件。
- -dontskipnonpubliclibraryclasses:指定不忽略非公共的库类。
- -dontskipnonpubliclibraryclassmembers:指定不忽略包可见的库类的成员。
- 2. 保留选项
- -keep {Modifier} {class_specif ication}:保护指定的类文件和类的成员。
- -keepclassmembers {modifier} {class_specification}:保护指定类的成员。
- -keepclasseswithmembers {class_specif ication}:保护指定的类和类的成员,但条件是所有指定的类和类成员要存在。
- -keepnames {class_specification}:保护指定的类和类的成员名称(如果不需要混淆)。
- -keepclassmembernames {class_specification}:保护指定的类的成员名称(不需要混淆)。
- -keepclassmembernames {class_specification}:保护指定的类的成员名称(不需要混淆)。
- -keepclasseswithmembernames {class_specification}:保护指定的类和类的成员名称,如果所有指定的类成员出席(在压缩步骤之后)。
- -printseeds {filename}:列出类和类的成员-keep选项的清单,标准输出到给定的文件。
- 3. 压缩
- -dontshrink:不压缩输入的类文件。
- -printusage {filename}:输出无用文件。
- 4. 优化
- -dontoptimize:不优化输入的类文件。
- -assumenosideeffects {class_specif ication}:优化时假设指定的方法,没有任何副作用。
- -allowaccessmodif ication:优化时允许访问并修改有修饰符的类和类的成员。 (5)混淆
- -dontobfuscate:不混淆输入的类文件。
- -printmapping {filename}:输出映射表。
- -applymapping {filename}:重用映射增加混淆。
- -obfuscationdictionary {filename}:使用给定文件中的关键字作为要混淆方法的名称。
- -overloadaggressively:混淆时应用侵入式重载。
- -useuniqueclassmembernames:确定统一的混淆类的成员名称来增加混淆。
- -renamesourcef ileattribute {string}:设置源文件中给定的字符串常量。
开启minifyEnabled混淆代码
在Android Studio中使用ProGuard
按照上一节的语法规则编写则编写proguard-rules.pro后,需要在build.gradle中配置,同时设置minifyEnabled为true,在编译工程时自动混淆代码,可大大减小APP大小,代码如下:
minifyEnabled 用开开启删除无用代码,比如没有引用到的代码
buildTypes {
debug {
minifyEnabled false
}
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles proguard-rules.pro'
}
}
3.2 资源优化
3.2.1 使用Android Lint
Android Lint工具可以用来扫描布局层级,Android Lint也能扫描到没有使用的资源文件。
- 资源文件最少化
系统根据不同分辨率会自动加载不同图片资源(ldpi、mdpi、tvdpi、hdpi、xhdpi、xxhdpi等),如果为了适配不同屏幕,每个文件夹都放一套图,对安装包大小的影响非常严重,虽然Android支持这么多的屏幕密度,但是不代表应用为每一个屏幕都提供一套资源,在这方面可以参考以下几个建议:
- 尽量使用一套图片资源,遇到一些图片在不同分辨率手机上变化差异过大的情况时,再考虑在相应文件夹下放入这个特定的图片。
- 使用一套图、一套布局、多套dimens.xml文件,在使用最小资源的情况下,解决多分辨率适配。
- 减少项目中的预设图片,预置图片改成服务器下发,尽可能将程序与资源分离。
- 删除无用so包
- armable-v7下so包
- 基本上armble的so也是兼容armable-v7的,armable-v7a的库会对图形渲染方面有很大的改进,如果没有这方面的要求,可以精简。
- x86包下的so包
- x86包下的so在x86型号的手机是需要的,如果产品没用这方面的要求也可以精简。建议实际工作的配置是只保留armable、armable-x86下的so文件,算是一个折中的方案。
- 删除无用的语言资源
- 大部分应用其实不需要支持多种语言的国际化,可以配置gradle的语言,比如国内应用只支持中文。
- armable-v7下so包
android {
defaultConfig {
resConfigs "zh"
}
}
3.2.2 清理无用资源
- Android 工具
- 使用AndroidStuido -> Refactor -> Remove Unused Resources 筛选出无用的资源文件
- 避免重复库
- 在应用开发中,比如几种图片开源库,可能一个开源库不能支持所有业务功能,而需要用到多个开源库,若一个应用放了两个图片库,不但增加了安装包大小,也增加了维护成本,此时,建议选择性价比更高、更适合当前应用业务需求的一个,在这个基础上增加相应的功能,扩展当前的图片库,而非引入新的开源库。
- 清理三方库和冗余代码
- 版本迭代过程中,因为删减功能经常有冗余代码和第三方库留下,这或多或少都会增加包体,这种情况没有捷径,只能每个文件查找,这是苦力活。还有要查看第三方库有没可能精简,比如谷歌分基础、广告和分析包,网络库、supportv4等,这个就具体情况具体分析。
- (比如使用ShareSDK的分享功能,图标和默认的分享弹窗都没有用到,引用时可以根据需求删减)
3.2.3 图片优化
- Android应用的资源中主要用到两种格式的图片:PNG和JPG。
- PNG(Portable Network Graphic Format)用来存储灰度图像时,灰度图像的深度可多到16位,存储彩色图像时,彩色图像的深度可多到48位,并且可存储多达16位的透明通道数据。
- JPG(JPEG)图片以24位颜色存储单个位图。JPEG是与平台无关的格式,支持最高级别的压缩,但这种压缩有损耗,并且没有透明通道。
- 在开发Android应用时,PNG资源图片在应用打包过程中,资源打包工具AAPT(Android Asset Packaging Tool)自动对PNG图片做压缩处理,但减小的大小比较有限,除了靠工具自动打包,一般还能采用以下两种方式。
- 降低图片色彩位数 如果使用的图片色彩比较单一,可以降低图像位数来减少图片大小。
- PNG图片压缩工具
对于非透明的大图,JPG文件会比PNG文件小很多,通常会减小到一半以上。一般使用于应用中的一些闪屏介绍页,全图背景等。
- 使用tinyPng压缩
- TinyPNG工具只支持上传PNG图片到官网上压缩,然后下载保存,在保持alpha通道的情况下对PNG的压缩可以达到1/3之内,而且用肉眼基本上分辨不出压缩的损失.
- Tinypng的官方网站:http://tinypng.com/
- 覆盖三方库里的大图
- 有些第三库里引用了一些大图但是实际上并不会被我们用到,就可以考虑用1x1的透明图片覆盖。
- 使用shape背景
- 特别是在扁平化盛行的当下,很多纯色的渐变的圆角的图片都可以用shape实现,代码灵活可控,省去了大量的背景图片。
- 使用着色方案
- 很多图片相似,只是颜色不同,可以通过着色方案减少图片的使用。
- 使用旋转方案
- 很多图片相似,只是方向不同,可以通过旋转图片减少图片的使用。
3.2.4 支持插件化
插件化除了可以解决方法数超标的问题,同时如果插件放到服务器,在需要时再下载下来,可以减少安装包大小。但是需要注意的是,因为使用时需要临时下载,所以建议在用户使用率不高的功能模块上使用,或者使用预加载。
4. 参考资料
- Android性能优化系列之apk瘦身
- 《Android应用性能优化最佳实践》罗彧成