【性能优化】也谈APK瘦身

前言

APK瘦身便是对APK大小进行压缩策略,减少APK安装包大小,更小的安装包更有助于吸引用户安装。前一段时间我司某一App进行APK的瘦身,最终也达到了减少10M的目标,现作一个简单的总结记录。android

如何着手这个问题?

须要对一个App进行瘦身,首先最重要的就是对App大小有一个大体的了解,最直观看到App的大小就是经过Android Studio自带的Analyzer进行APK的分析。使用方法:web

一、将一个apk拖动到Android Studio的编辑器窗口 
二、在Project窗口中,双击build/output/apks/目录下的apk 
三、在菜单栏中选择选择Build > Analyze APK,而后选择要分析的apk
复制代码

获取如上图1所示的APK Size分析图以后,咱们就能够针对这里面的目录进行针对性的优化。面试

如图最上方所示的APK Size就是咱们应用打包以后的大小,Download Size则是上传到Google Play以后,用户下载的大小。因此咱们通常能够只针对前一项的APK Size进行对比。安全

分析问题,发掘优化点

从上图Analyzer能够发现,一个APK主要包含以下目录:bash

  • **lib:**包含了一些区分于处理器的编译代码,主要是SO文件,通常里面包含不少子目录,例如armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, and mips。
  • **res:**包含了一些不会被编译到resources.arsc的资源文件。如drawable文件、layout文件等。
  • **assets:**包含了一些经过AssetManager可以检索到的资源。如MP三、字体、webp等资源文件。
  • **META-INF:**包含了CERT.SF和CERT.RSA签名文件,还有MANIFEST.MF文件。

除此以外,还包含了以下的文件:微信

  • **resources.arsc:**包括了全部能够被编译的位于res/values/目录下的XML资源。打包工具在打包过程当中会把XML的内容编译成二进制的形式,亦或者把相关资源的引用路径编译成二进制,而后整合到该文件里面。例如string文件、layout的路径、图片的路径等。
  • **classes.dex:**包含了全部的Java文件编译后的class文件,class文件最终转化成该dex文件。通常文件都比较大,有的App有几个dex文件,这是由于单个DEX文件限制方法数在65536,因此当代码量过大时,就须要经过multiDex进行分包,拆分红多个dex文件,解决这个问题。
  • **AndroidManifest.xml:**整合了多个module的AndroidMainifest文件的权限、声明等配置到该文件。

知道了APK的组成部分,那么咱们就能够针对这些文件/文件夹进行针对性的优化,每一个App都不同,可是方法都是大同小异,本文讲述瘦身策略也是针对这些目录和文件进行优化,这样能够显得更加有条理性。架构

1. lib目录优化

Android系统如今支持7种CPU架构,每一种都关联着对应的ABI(二进制接口,Application Binary Interface),而每一种ABI都定义了二进制文件(尤为是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库等。因此若是咱们的App须要适配不一样的CPU架构的话,以下图2所示,就须要放入不一样架构的文件夹下都放入不一样的so文件,在打包时,这些so都会放在lib目录下。由此,若是咱们想减少lib目录的大小,无非就以下一些常见的策略。app

  • so裁剪、删除

对App引入的so文件进行确认哪些是不须要的,哪些是能够进行裁剪压缩的,哪些是能够避免引入的。例如若是引入的so须要下载上传功能而多引入了一个cURL库致使so增大,这时就可让Java层代码定义接口,让so来调用,从而避免引入cURL库;再如Fresco库,若是不须要webP图,或者不须要webP动图功能,而后减小Fresco库的依赖,一样能够减少so的大小。编辑器

  • 只保留armeabi或者armeabi-v7a

Android系统如今支持不少种CPU架构(如mips、arm、x86等),市面上主流机型都是arm架构,x86和mips类型极少。因此能够有选择地保留某些架构的so,从而下降lib文件夹的大小。可是我建议你在开始前先对用户手机的cpu型号进行一次统计,分析自身App对应架构手机的占有率,这样你才能大胆的进行操做,通常只保留armeabi或者armeabi-v7a便可。操做也是比较简单,只须要在根目录的build.gradle下配置:函数

android {
    buildTypes {
        ndk {
            abiFilters "armeabi-v7a"
        }
    }
}` 
复制代码

若是你的App须要支持多种架构,那么就能够在abiFilters里面把多种架构加进去,固然你也能够只保留一种,而后分渠道打包,如Google Play就支持arm和x86等多个渠道打包。

2.res目录优化

res目录通常也是占APK Size大头的一个目录,以下图,这个目录通常都是图片资源占空间比较多,尤为当App为了适配多种分辨率而存放了多套图时,这时候就会致使res目录打下会很是大。而这个目录的优化方式也是比较多,下面就简单列举一下:

  • 只保留一套图

由于Android设备在加载图片时会优先加载对应分辨率文件夹下的图片,若是对应分辨率文件下没有所要的图片,则找高分辨率对应文件夹下的图片。那是否是咱们把图片放在最高分辨率的文件夹下就能够了呢?不是的!由于若是这样会致使低分辨率手机加载图片时会消耗更多的内存,并且是指数级别增加的,因此若是盲目地放在一个目录是不合适的。目前不一样分辨率对应优先加载的文件夹中图片以下,若是是针对国内用户的App能够只保留xxhdpi目录,而若是是东南亚市场的App则能够只保留xhdpi。

320*240        ldpi

480*320        mdpi

800*480        hdpi

1280*720       xhdpi

1920*1080      xxhdpi` 
复制代码
  • 非重要图片动态加载

针对一些非重要的图片,能够选择动态在线加载,严格来讲,非首页的图片均可以动态加载,固然,为了提高用户体验,咱们会把图片放在本地。可是,一些使用场景很是小或者大小较大的图片,大胆删掉,选择动态加载吧!

  • 保真压缩图片

可使用一些图片压缩网站或者工具压缩你的资源文件吧,例如TinyPng、ImageOptim、Zopfli、智图等。

  • 使用webp替换png

若是你的App只支持Android4.0以上的话,能够把png格式的图片转为webp,相同画质下体积更小。

  • 使用lint删除无用资源

在多人开发过程当中,一般都会有漏删无用资源的问题,图片资源也不例外,例如须要删除一个模块的代码时,很容易就会漏删资源文件,因此能够按期使用lint检测出无用的资源文件,原理这里不做介绍,使用方法很是简单,能够直接在AS里面使用,以下图所示。注意:lint检查出来的资源都是无直接引用的,因此若是咱们经过getIdentifier()方法引用文件时,lint也会标记为无引用,因此删除时注意不要删除经过getIdentifier()引用的资源。

Analyze -> Run Inspection by Name -> 输入:Unused resources ->
跳出弹框选择范围便可
复制代码
  • 打开shrinkResources

shrinkResources是在编译过程当中用来检测并删除无用资源文件,也就是没有引用的资源,minifyEnabled 这个是用来开启删除无用代码,好比没有引用到的代码,因此若是须要知道资源是否被引用就要配合minifyEnabled使用,只有二者都为true时才会起到真正的删除无效代码和无引用资源的目的。打开方式也是很是简单,在build.gralde文件里面打开便可:

android {
    buildTypes{
        minifyEnabled true
        shrinkResources true
    }
}` 
复制代码

3.assests目录优化

assests目录存放的一般是一些经过AssetManager可以检索到的资源,包括MP三、视频、字体、webp的资源,各个App存放内容都很大不相同,列举一些经常使用的优化方案。

  • 删除无用字体

中文字体通常都比较大,由于字体文件包含了中文好几千个汉字,可是咱们实际上在App中并不会所有都使用,甚至咱们只用到其中的几个字,这时候咱们就能够把字体文件进行删减,在Github上面有一个字体提取工具FontZip,使用方法也是很是简单,有兴趣能够去star一下。

  • 动态下载

一些MP三、视频、Webp等资源能够在使用到时再进行下载,不须要放在本地。

  • 对资源进行压缩

一些MP三、视频、Webp等资源若是必须放在本地,能够压缩成zip文件或者使用7zip进行压缩,在使用到时再进行解压,减少空间的占用。

4.META-INF目录

该目录下的MANIFEST.MF、CERT.SF、INDEX.LIST、CERT.RSA等文件主要是存放一些APK文件加密后的信息,用以校验APK的完整性和安全性,这个目录没有太好的优化方式,并且文件通常也比较小,不会超过1M。

5.resources.arsc文件压缩

这个文件包含全部能够被编译的位于res/values/目录下的XML资源,以下图5所示是淘宝APK的resources.arsc文件,像图片的引用名字、layout文件的引用名字、string资源等都被编译到了这个文件里面。

因此若是咱们须要对resources.arsc文件进行优化,无非就是对路径名字进行混淆,删除无用的资源映射,前者可使用AndResGuard,后者可使用lint等进行检测。

  • 删除无用的语言

大部分应用都不须要支持几十种上百种语言,因此在咱们引用一些第三方库时(如Google、Facebook的库),它们每每带有上百种多语言资源,而大部分多语言对于咱们本身的应用是没有用处的,咱们只须要在build.gralde里面进行以下配置便可完成无用语言资源的删除,这样在打包的时候就会排除私有项目、android系统库和第三方库中非中文的资源文件了,效果仍是比较显著的。

android {
    //...
    defaultConfig {
        // 只保留中文
        resConfigs "zh"
    }
}` 
复制代码
  • 使用AndResGuard压缩

AndResGuard是一个帮助你缩小APK大小的工具,他的原理相似Java Proguard,可是只针对资源。他会将本来冗长的资源路径变短,例如将res/drawable/wechat变为r/d/a。详细使用方法参照Github,很简单有效地减少resources.arsc文件大小。以下图6和图7所示,图6是压缩前的效果,图7是压缩完的效果,若是是资源比较多的App,压缩效果也是立竿见影。

使用方法也是很是简单,在build.gradle文件中进行以下配置便可:

andResGuard {
    mappingFile = null
    use7zip = true
    useSign = true
    keepRoot = false
    whiteList = [
        //for your icon
        "R.drawable.icon",
        //for fabric
        "R.string.com.crashlytics.*",
        //for umeng update
        "R.string.umeng*",
        "R.string.UM*",
        "R.layout.umeng*",
        "R.drawable.umeng*",
        //umeng share for sina
        "R.drawable.sina*"
    ]
    compressFilePattern = [
        "*.png",
        "*.jpg",
        "*.jpeg",
        "*.gif",
        "resources.arsc"
    ]
     sevenzip {
         artifact = 'com.tencent.mm:SevenZip:1.1.9'
         //path = "/usr/local/bin/7za"
    }
}` 
复制代码

6.dex文件压缩

Dalvik是Android平台运行时的环境,可是Dalvik虚拟不支持直接执行Java的字节码,因此会对编译生成的 .class 文件进行翻译、重构、解释、压缩等处理,这个处理过程是由 dx 进行处理,处理完成后生成的产物会以 .dex 结尾,称为Dex文件。

像淘宝、微信这些App,若是咱们分析它们的APK能够发现,它们有多个Dex文件,以下图8所示,这是由于单个Dalvik Excutable(DEX)字节码文件内的方法数不能够超过65536个,因此须要DEX分包配置来避免这个限制,使应用可以构建并读取DEX文件。

  • Proguard代码混淆

Proguard是一款免费的Java类文件压缩器、优化器和混淆器,Android Studio已经集成了这个工具,只要通过简单的配置,便可完成,以下代码所示,在build.gradle里面设置minifyEnabled为ture,同时在proguardFiles指向proguard的规则文件便可。

android {
    buildTypes{
        minifyEnabled true
        proguardFiles 'proguard.cfg'
    }
}` 
复制代码

总结

App瘦身是一个长期的过程,建议能够进行每一个版本对APK大小进行监控,列出增长和减少的点,作到持续的统计和追踪,从而给公司带来效益。

按期分享Android高级技术和面试分享,欢迎关注,喜欢文章的朋友点个赞叭~

相关文章
相关标签/搜索