APK瘦身-是时候给App进行减负了
前言
APK瘦身即是对APK大小进行压缩策略,减小APK安装包大小,更小的安装包更有助于吸引用户安装。前一段时间我司某一App进行APK的瘦身,最终也达到了减小10M的目标,现做一个简单的总结记录。
如何着手这个问题?
需要对一个App进行瘦身,首先最重要的就是对App大小有一个大致的了解,最直观看到App的大小就是通过Android Studio自带的Analyzer进行APK的分析。使用方法:
1、将一个apk拖动到Android Studio的编辑器窗口
2、在Project窗口中,双击build/output/apks/目录下的apk
3、在菜单栏中选择选择Build > Analyze APK,然后选择要分析的apk
获取如上图1所示的APK Size分析图之后,我们就可以针对这里面的目录进行针对性的优化。
如图最上方所示的APK Size就是我们应用打包之后的大小,Download Size则是上传到Google Play之后,用户下载的大小。所以我们一般可以只针对前一项的APK Size进行对比。
分析问题,发掘优化点
从上图Analyzer可以发现,一个APK主要包含如下目录:
- lib:包含了一些区分于处理器的编译代码,主要是SO文件,一般里面包含很多子目录,例如armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, and mips。
- res:包含了一些不会被编译到resources.arsc的资源文件。如drawable文件、layout文件等。
- assets:包含了一些通过AssetManager能够检索到的资源。如MP3、字体、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目录的大小,无非就如下一些常见的策略。
- 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能够检索到的资源,包括MP3、视频、字体、webp的资源,各个App存放内容都很大不相同,列举一些常用的优化方案。
- 删除无用字体
中文字体一般都比较大,因为字体文件包含了中文好几千个汉字,但是我们实际上在App中并不会全部都使用,甚至我们只用到其中的几个字,这时候我们就可以把字体文件进行删减,在Github上面有一个字体提取工具FontZip,使用方法也是非常简单,有兴趣可以去star一下。
- 动态下载
一些MP3、视频、Webp等资源可以在使用到时再进行下载,不需要放在本地。
- 对资源进行压缩
一些MP3、视频、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大小进行监控,列出增加和减小的点,做到持续的统计和追踪,从而给公司带来效益。
APK瘦身-是时候给App进行减负了的更多相关文章
- 39、apk瘦身(转载)
本文转自::Android开发中文站 » 关于APK瘦身值得分享的一些经验 从APK的文件结构说起 APK在安装和更新之前都需要经过网络将其下载到手机,如果APK越大消耗的流量就会越多,特别是对于使用 ...
- APK瘦身记,如何实现高达53%的压缩效果
作者:非戈@阿里移动安全 1.我是怎么思考这件事情的 APK是Android系统安装包的文件格式,关于这个话题其实是一个老生常谈的题目,不论是公司内部,还是外部网络,前人前辈已经总结出很多方法和规律. ...
- APK瘦身实践
首发地址:http://www.jayfeng.com/2015/12/29/APK%E7%98%A6%E8%BA%AB%E5%AE%9E%E8%B7%B5/ 因为推广的需要,公司需要把APK的大小再 ...
- APK瘦身
APK瘦身 主要从一下三方面来瘦身: 1. Java 源代码 1) ,这方面主要是通过最简洁的代码实现最直接的功能,还有就是提出上线前不必要的java代码,可以使用UCDector进行分析,从而对代码 ...
- Android APK 瘦身 - JOOX Music项目实战
导语 JOOX Music是腾讯海外布局的一个音乐产品,2014年发布以来已经成为5个国家和地区排名第一的音乐App.东南亚是JOOX Music的主要发行地区,由于JOOX Music所面对的市场存 ...
- Android性能优化系列之apk瘦身
Android性能优化系列之布局优化 Android性能优化系列之内存优化 为什么APK要瘦身.APK越大,在下载安装过程中.他们耗费的流量会越多,安装等待时间也会越长:对于产品本身,意味着下载转化率 ...
- 安卓APK瘦身
之前打包的时候直接就用eclipse或者android studio直接生成签名文件,并没有关心大小问题,近期有人问我有没有对APK进行瘦身.对这方面内容一致没有关注过,今天试用了各种方式把项目签名a ...
- APK瘦身记,怎样实现高达53%的压缩效果
作者:非戈@阿里移动安全,很多其它技术干货.请訪问阿里聚安全博客 1.我是怎么思考这件事情的 APK是Android系统安装包的文件格式.关于这个话题事实上是一个老生常谈的题目.不论是公司内部.还是外 ...
- Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android XML shape 标签使用详解 一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...
随机推荐
- 图像处理之基础---boxfiter
http://blog.sina.com.cn/s/blog_7221228801019yg2.html DSP6000图像位移与变形典型算法 http://blog.csdn.net/anson20 ...
- [学习笔记]overthewire bandit 通关秘籍
1.第一关 使用putty等工具连入linux即可,注意port等设置. ls 列目录内文件: cat readme,显示文件内容,即可看到密码. 2.第二关 如何查看文件名为-的文件? cat ./ ...
- Cron Expression
CronTrigger CronTriggers往往比SimpleTrigger更有用,如果您需要基于日历的概念,而非SimpleTrigger完全指定的时间间隔,复发的发射工作的时间表.CronTr ...
- p_CreateAuditEntry
如果你能搜到我这篇博客,相信你导遇到的了和我一样在导入CRM组织时遇到了类似的错误.这个错误我查资料可以通过CRM升级来解决参考下面连接: https://support.microsoft.com/ ...
- mysql04--存储过程
过程:若干语句,调用时执行封装的体.没有返回值的函数. 函数:是一个有返回值的过程 存储过程:把若干条sql封装起来,起个名字(过程),并存储在数据库中. 也有不存储的过程,匿名过程,用完就扔(mys ...
- HDU1087 Super Jumping! Jumping! Jumping! —— DP
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1087 Super Jumping! Jumping! Jumping! Time Limi ...
- java中abstract和interface的區別(轉)
(一)概述 在Java语言中, abstract class 和interface 是支持抽象类定义的两种机制.正是由于这两种机制的存 在,才赋予了Java强大的 面向对象能力.abstract ...
- mysql查询表的字符集
mysql查询表的字符集 SHOW CREATE TABLE user;
- android ndk环境搭建,如果是mac,请先装mac make编译器(可以使用Xcode进行安装)
Android SDK:android-sdk-mac_86Android NDK: android-ndk-r4b-darwin-x86EclipseADTCDTANT搭建Android SDK开发 ...
- bzoj3251
3251: 树上三角形 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 637 Solved: 262[Submit][Status][Discuss ...