在平常开发过程中,随着应用功能不断增加和版本功能迭代,APK的体积大小在不知不觉中不断增大,而APK体积大小会影响用户首次下载安装应用或更新应用的时长和流量消耗。因此,如何有效合理的优化APK的体积也是在平常开发中需要留意的。
一、合理选择图片类型
在APP中图片就占据了很大的一部分体积,所以图片的优化是我们必须要关注的点。
平常使用到的图片类型主要有jpg、png、webp、svg等。
-
jpg是有损压缩格式,使用的一种失真压缩标准方法,24 bit真彩色,内容比GIF丰富,不支持动画、不支持透明色。
-
png是无损压缩格式,PNG格式有8位、24位、32位三种形式,其中8位PNG支持两种不同的透明形式(索引透明和alpha透明),24位PNG不支持透明,32位PNG在24位基础上增加了8位透明通道(32-24=8),因此可展现256级透明程度。
-
webp的优势体现在它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量;同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性。
-
svg是可缩放矢量图,SVG不会像位图一样因为缩放而让图片质量下降。优点在于可以减小APK的大小,在使用过程中可以使用tink属性变化颜色,建议用于图标大小在200dp*200dp的简单小图标以内。
因此,小图标的文件类型我们优先选择svg相对其他文件类型可以有效减少APK大小。
此外,在Android中使用svg格式的图片需要留意以下两点:
1.svg是由xml定义的,标准svg根节点为<svg>
。Android中只支持<vector>
,我们需要通过 vector 将svg的根节点 <svg>
转换为 <vector>
。
2.Android 5.0之前的版本不支持矢量图,需要向后兼容。
2.1.在 build.gradle 中配置如下,
android{
// Gradle Plugin 2.0+
defaultConfig{
// 利用支持库中的 VectorDrawableCompat 类,可实现 2.1 版本及更高版本中支持 VectorDrawable
vectorDrawables.useSupportLibrary = true
}
}
dependencies {
// 支持库版本需要是 23.2 或更高版本
compile 'com.android.support:appcompat-v7:23.2.0'
}
2.2 使用 app:srcCompat 属性代替 android:src
二、移除无用资源
在需求功能变更和版本迭代的过程中,难免会产生无用的旧资源
1.通过Android Studio提供的Remove Unused Resources可以帮助我们查找出无用资源。
点击Preview按钮预览一下查询出来的资源。搜索结果如下:
2.通过Lint工具查找无用资源
输入Unused resources快速找到Lint工具
默认查询范围整个项目,直接点OK
查找结果如下
左边列表展示搜索到的无用资源,右边列表可以对资源单独做处理,具体如下:
第二种方式的可操作性比第一种好,因此推荐使用Lint方式去移除无效资源
三、压缩代码
在app目录下的build.gradle打开压缩代码功能
buildTypes {
release {
minifyEnabled true //打开代码压缩
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled true//打开代码压缩
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
对比如下:
四、压缩资源
压缩资源功能需要搭配压缩代码一起使用
buildTypes {
release {
shrinkResources true//打开资源压缩
minifyEnabled true//打开代码压缩
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
shrinkResources true//打开资源压缩
minifyEnabled true//打开代码压缩
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
效果如下:
压缩资源可以自定义要保留的资源,具体步骤为创建keep.xml
文件,存放位置为res/raw/keep.xml
(构建系统不会将此文件打包到 APK 中)。在 tools:keep
属性中指定每个要保留的资源,在 tools:discard
属性中指定每个要舍弃的资源。这两个属性都接受以逗号分隔的资源名称列表。您可以将星号字符用作通配符。如下:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
tools:discard="@layout/unused2" />
五、资源混淆压缩
资源混淆的原理是通过修改APK包里的resource.arsc文件,修改文件中的字符串池中的字符串,将其修改为简单短小的字符串,以此来减少文件大小,如下图:
可以使用微信的开源的AndResGuard进行压缩,具体步骤如下
- 1.修改project目录下的build.gradle
dependencies {
classpath "com.android.tools.build:gradle:4.0.0"
//引入AndResGuard
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.18'
}
- 2.project目录下新建andresguard.gradle
内容如下:
apply plugin: 'AndResGuard'
andResGuard {
mappingFile = null
use7zip = true
useSign = true
keepRoot = false
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
"resources.arsc"
]
whiteList = [
// your icon
"R.drawable.icon",
// for fabric
"R.string.com.crashlytics.*",
// for umeng update
"R.string.tb_*",
"R.layout.tb_*",
"R.drawable.tb_*",
"R.drawable.u1*",
"R.drawable.u2*",
"R.color.tb_*",
// umeng share for sina
"R.drawable.sina*",
// for google-services.json
"R.string.google_app_id",
"R.string.gcm_defaultSenderId",
"R.string.default_web_client_id",
"R.string.ga_trackingId",
"R.string.firebase_database_url",
"R.string.google_api_key",
"R.string.google_crash_reporting_api_key",
]
sevenzip {
artifact = 'com.tencent.mm:SevenZip:1.2.10'
//path = "/usr/local/bin/7za"
}
}
- 3.app目录下的build.gradle引入andresguard.gradle
apply from: "${rootProject.rootDir}/andresguard.gradle"
配置编译完成后可以看到增加了andresguard的相关Task
点击resguradDebug打包,跟之前的apk做对比,结果如下:
以上五种优化方式基本所有APP都通用,以下的优化方式需要根据项目实际应用情况合理选择。
六、国际化配置优化
假如APP只在一个国家或者只针对一种语言做适配,不需要做国际化配置的情况下,可以在app下的build.gradle增加如下配置,移除第三方SDK的国际化配置,减少APP体积:
android{
defaultConfig{
// 适配默认语言英语
resConfigs 'en'
}
}
配置后APK大小前后对比如下:
七、so库打包优化
so文件是由ndk编译出来的动态库,每一个平台需要使用对应的so库。
ABI 是应用程序二进制接口简称(Application Binary Interface),定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。
在Android 系统上,每一个CPU架构对应一个ABI:armeabi,armeabi-v7a,arm64- v8a,x86,x86_64,mips,mips64。
目前市面上主流的手机中,基本都是使用基于armeabi-v7a的CPU架构,因此我们只需要配置armeabi-v7a就可以了。
如果已经确定APP只运行在某个设备上,也可以直接配置对应的ABI。
配置代码如下:
android{
defaultConfig{
ndk{
abiFilters "armeabi-v7a"
}
}
}