Android优化篇之APK体积优化

在平常开发过程中,随着应用功能不断增加和版本功能迭代,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可以帮助我们查找出无用资源。

Remove Unused Resources.png
选项.png

点击Preview按钮预览一下查询出来的资源。搜索结果如下:


搜索结果.png

2.通过Lint工具查找无用资源

Lint.png

输入Unused resources快速找到Lint工具

Unused resources.png

默认查询范围整个项目,直接点OK


默认.png

查找结果如下


查找结果.png

左边列表展示搜索到的无用资源,右边列表可以对资源单独做处理,具体如下:
处理.png

第二种方式的可操作性比第一种好,因此推荐使用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'
        }
    }

对比如下:


未开启代码压缩.png
开启代码压缩.png

四、压缩资源

压缩资源功能需要搭配压缩代码一起使用

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'
        }
    }

效果如下:

代码压缩和资源压缩.png

压缩资源可以自定义要保留的资源,具体步骤为创建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文件,修改文件中的字符串池中的字符串,将其修改为简单短小的字符串,以此来减少文件大小,如下图:


资源混淆压缩原理.png

可以使用微信的开源的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


    andresguard.gradle.png

内容如下:

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

Taskpng

点击resguradDebug打包,跟之前的apk做对比,结果如下:


未压缩.png

压缩后.png

以上五种优化方式基本所有APP都通用,以下的优化方式需要根据项目实际应用情况合理选择。

六、国际化配置优化

假如APP只在一个国家或者只针对一种语言做适配,不需要做国际化配置的情况下,可以在app下的build.gradle增加如下配置,移除第三方SDK的国际化配置,减少APP体积:

android{
    defaultConfig{
        // 适配默认语言英语
        resConfigs 'en'
    }
}

配置后APK大小前后对比如下:


未做国际化配置优化.png

做国际化配置优化后.png

七、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"
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352