为何APK要瘦身。APK越大,在下载安装过程当中,他们耗费的流量会越多,安装等待时间也会越长;对于产品自己,意味着下载转化率会越低(由于竞品中,用户有更多机会选择那个体验最好,功能最多,性能最好,包最小的),因此apk的瘦身优化也很重要,本文将讲述apk瘦身的相关内容。android
在Android Studio工具栏里,打开build–>Analyze APK, 选择要分析的APK包git
能够看到占用空间的主要是代码、图片、资源和lib和assert文件,主要方向精简代码、压缩图片、去除无用的库、减小asserts里面文件。github
对于绝大对数APP来讲,只须要取一套设计图就足够了。鉴于如今分辨率的趋势,建议取720p的资源,放到xhdpi目录。 相对于多套资源,只使用720P的一套资源,在视觉上差异不大,不少大公司的产品也是如此,但却能显著的减小资源占用大小,顺便也能减轻设计师的出图工做量了。 注意,这里不是说把不是xhdpi的目录都删除,而是强调保留一套设计资源就够了。web
在gradle使用minifyEnabled进行Proguard混淆的配置,可大大减少APP大小:bash
android {
buildTypes {
release {
minifyEnabled true
}
}
}
复制代码
在proguard中,是否保留符号表对APP的大小是有显著的影响的,可酌情不保留,可是建议尽可能保留用于调试。微信
参数:网络
-include {filename} 从给定的文件中读取配置参数
-basedirectory {directoryname} 指定基础目录为之后相对的档案名称
-injars {class_path} 指定要处理的应用程序jar,war,ear和目录
-outjars {class_path} 指定处理完后要输出的jar,war,ear和目录的名称
-libraryjars {classpath} 指定要处理的应用程序jar,war,ear和目录所须要的程序库文件
-dontskipnonpubliclibraryclasses 指定不去忽略非公共的库类。
-dontskipnonpubliclibraryclassmembers 指定不去忽略包可见的库类的成员。
复制代码
保留选项架构
-keep {Modifier} {class_specification} 保护指定的类文件和类的成员
-keepclassmembers {modifier} {class_specification} 保护指定类的成员,若是此类受到保护他们会保护的更好
-keepclasseswithmembers {class_specification} 保护指定的类和类的成员,但条件是全部指定的类和类成员是要存在。
-keepnames {class_specification} 保护指定的类和类的成员的名称(若是他们不会压缩步骤中删除)
-keepclassmembernames {class_specification} 保护指定的类的成员的名称(若是他们不会压缩步骤中删除)
-keepclasseswithmembernames {class_specification} 保护指定的类和类的成员的名称,若是全部指定的类成员出席(在压缩步骤以后)
-printseeds {filename} 列出类和类的成员-keep选项的清单,标准输出到给定的文件
复制代码
压缩app
-dontshrink 不压缩输入的类文件
-printusage {filename}
-whyareyoukeeping {class_specification}
复制代码
优化ide
-dontoptimize 不优化输入的类文件
-assumenosideeffects {class_specification} 优化时假设指定的方法,没有任何反作用
-allowaccessmodification 优化时容许访问并修改有修饰符的类和类的成员
复制代码
混淆
-dontobfuscate 不混淆输入的类文件
-printmapping {filename}
-applymapping {filename} 重用映射增长混淆
-obfuscationdictionary {filename} 使用给定文件中的关键字做为要混淆方法的名称
-overloadaggressively 混淆时应用侵入式重载
-useuniqueclassmembernames 肯定统一的混淆类的成员名称来增长混淆
-flattenpackagehierarchy {package_name} 从新包装全部重命名的包并放在给定的单一包中
-repackageclass {package_name} 从新包装全部重命名的类文件中放在给定的单一包中
-dontusemixedcaseclassnames 混淆时不会产生形形色色的类名
-keepattributes {attribute_name,...} 保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-renamesourcefileattribute {string} 设置源文件中给定的字符串常量
复制代码
在gradle使用shrinkResources去除无用资源,效果很是好。
android {
buildTypes {
release {
shrinkResources true
}
}
}
复制代码
版本迭代过程当中,不但有废弃代码冗余,确定会有无用的图片存在。在build.gradle 里面配置shrinkResources true,在打包的时候会自动清除掉无用的资源,但通过实验发现打出的包并不会,而是会把部分无用资源用更小的东西代替掉。注意,这里的“无用”是指调用图片的全部父级函数最终是废弃代码,而shrinkResources true 只能去除没有任何父函数调用的状况,真正起效果只能经过Android Studio自带的 “Remove Unused Resources”小插件来实现了,直接上图。
更人性化是该查找结果能够“一键删除”。固然,可能图片是通过反射或字符拼接等方式获取,因此这个检测列表也不是全对,删除后很大几率编译失败或部分页面挂死、无图等问题,这个无解,工具还没智能到这个地步,你只能一遍又一遍“编译—解决部分问题—再编译再”,别问我为何知道。
大部分应用其实并不须要支持几十种语言的国际化支持。还好强大的gradle支持语言的配置,好比国内应用只支持中文:
android {
defaultConfig {
resConfigs "zh"
}
}
复制代码
TinyPNG工具只支持上传PNG图片到官网上压缩,而后下载保存,在保持alpha通道的状况下对PNG的压缩能够达到1/3以内,并且用肉眼基本上分辨不出压缩的损失. Tinypng的官方网站:tinypng.com/
若是对于非透明的大图,jpg将会比png的大小有显著的优点,虽然不是绝对的,可是一般会减少到一半都不止。 在启动页,活动页等之类的大图展现区采用jpg将是很是明智的选择。
webp支持透明度,压缩比比jpg更高但显示效果却不输于jpg,官方评测quality参数等于75均衡最佳。 相对于jpg、png,webp做为一种新的图片格式,限于android的支持状况暂时还没用在手机端普遍应用起来。从Android 4.0+开始原生支持,可是不支持包含透明度,直到Android 4.2.1+才支持显示含透明度的webp,使用的时候要特别注意。 官方介绍:developers.google.com/speed/webp/…
若是通过上述步骤以后,你的工程里面还有一些大图,考虑是否有必要维持这样的大尺寸,是否能适当的缩小。 事实上,因为设计师出图的缘由,咱们拿到的不少图片彻底能够适当的缩小而对视觉影响是极小的。
有些第三库里引用了一些大图可是实际上并不会被咱们用到,就能够考虑用1x1的透明图片覆盖。 你可能会有点不舒服,由于你的drawable下居然包含了一些莫名其妙的名称的1x1图片…
基本上armable的so也是兼容armable-v7的,armable-v7a的库会对图形渲染方面有很大的改进,若是没有这方面的要求,能够精简。 这里不排除有极少数设备会Crash,可能和不一样的so有必定的关系,请你们务必测试周全后再发布。
与第十条不一样的是,x86包下的so在x86型号的手机是须要的,若是产品没用这方面的要求也能够精简。 建议实际工做的配置是只保留armable、armable-x86下的so文件,算是一个折中的方案。
微信资源压缩打包工具经过短资源名称,采用7zip对APP进行极致压缩实现减少APP的目标,效果很是的好,强烈推荐。
建议开启7zip,注意白名单的配置,不然会致使有些资源找不到,官方已经发布AndResGuard到gradle中了,很是方便:
apply plugin: 'AndResGuard'
buildscript {
dependencies {
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.1.7'
}
}
andResGuard {
mappingFile = null
use7zip = true
useSign = true
keepRoot = false
// add <your_application_id>.R.drawable.icon into whitelist.
// because the launcher will get thgge icon with his name
def packageName = <your_application_id>
whiteList = [
//for your icon
packageName + ".R.drawable.icon",
//for fabric
packageName + ".R.string.com.crashlytics.*",
//for umeng update
packageName + ".R.string.umeng*",
packageName + ".R.string.UM*",
packageName + ".R.string.tb_*",
packageName + ".R.layout.umeng*",
packageName + ".R.layout.tb_*",
packageName + ".R.drawable.umeng*",
packageName + ".R.drawable.tb_*",
packageName + ".R.anim.umeng*",
packageName + ".R.color.umeng*",
packageName + ".R.color.tb_*",
packageName + ".R.style.*UM*",
packageName + ".R.style.umeng*",
packageName + ".R.id.umeng*"
]
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
"resources.arsc"
]
sevenzip {
artifact = 'com.tencent.mm:SevenZip:1.1.7'
//path = "/usr/local/bin/7za"
}
}
复制代码
会生成一个andresguard/resguard的Task,自动读取release签名进行从新混淆打包。
对于一些库是按照须要动态的加载,可能在某些版本并不须要,可是代码又不方便去除不然会编译不过。 使用provided能够保证代码编译经过,可是实际打包中并不引用此第三方库,实现了控制APP大小的目标。 可是也同时就须要开发者本身判断不引用这个第三方库时就不要执行到相关的代码,避免APP崩溃。
矢量图是由点与线组成,和位图不同,它再放大也能保持清晰度,并且使用矢量图比位图设计方案能节约30~40%的空间,如今谷歌一直在强调扁平化方式,矢量图可很好的契合该设计理念。 —优点 1.占用存储空间小 2.无极拉伸不会出现锯齿,能够照顾不一样尺寸的机型 3.Android Studio自带不少资源,减少UI工做量 —劣势 1.只支持5.0及以上系统 2.与位图相比多了一层计算,需消耗更多性能 3.不支持.9图 4.不适合表现真实照片和复杂图形,通常使用在简单的icon和动画上
特别是在扁平化盛行的当下,不少纯色的渐变的圆角的图片均可以用shape实现,代码灵活可控,省去了大量的背景图片。
相信你的工程里也有不少selector文件,也有不少类似的图片只是颜色不一样,经过着色方案咱们能大大减轻这样的工做量,减小这样的文件。 借助于android support库可实现一个全版本兼容的着色方案。
若是你的APP支持素材库(好比聊天表情库)的话,考虑在线加载模式,由于每每素材库都有不小的体积。 这一步须要开发者实如今线加载,一方面增长代码的复杂度,一方面提升了APP的流量消耗,建议酌情选择。
避免重复库看上去是理所固然的,可是秘密老是藏的很深,必定要小心你引用的第三方库又引用了哪一个第三方库,这就很容易出现功能重复的库了,好比使用了两个图片加载库:Glide和Picasso。 经过查看exploded-aar目录和External Libraries或者反编译生成的APK,尽可能避免重复库的大小,减少APP大小。
版本迭代过程当中,由于删减功能常常有冗余代码和第三方库留下,这或多或少都会增长包体,这种状况没有捷径,只能每一个文件查找,这是苦力活。还有要查看第三方库有没可能精简,好比谷歌分基础、广告和分析包,网络库、supportv4等,这个就具体状况具体分析,很少阐述。
插件化技术支持动态的加载代码和动态的加载资源,把APP的一部分分离出来了,对于业务庞大的项目来讲很是有用,极大的分解了APP大小。 由于插件化技术须要必定的技术保障和服务端系统支持,有必定的风险,如无必要(好比一些小型项目,也没什么扩展业务)就不须要了,建议酌情选择。
redex是facebook发布的一款android字节码的优化工具,须要按照说明文档自行配置一下。 ··· redex input.apk -o output.apk --sign -s -a -p ··· 下面咱们来看看它的效果,仅redex的话,减少了157k:
若是先进行微信混淆,再redex,减少了565k,redex只贡献了10k:
若是先进行redex,在进行微信混淆,减少了711k,redex贡献了157k:
最后一种的效果是最好的,这是很容易解释的,若是最后是redex的从新打包则浪费了前面的7zip压缩,因此为了最优效果要注意顺序。 另外,据反应redex后会有崩溃的现象,这个要留意一下,我这里压缩以后都是能够正常运行的。 详情参考:ReDex
若是你看到了这里,以为文章写得不错就给个赞呗?若是你以为那里值得改进的,请给我留言。必定会认真查询,修正不足。谢谢。
但愿读到这的您能转发分享和关注一下我,之后还会更新技术干货,谢谢您的支持!
转发+点赞+关注,第一时间获取最新知识点
Android架构师之路很漫长,一块儿共勉吧!