概述

为什么APK要瘦身。APK越大,在下载安装过程中,他们耗费的流量会越多,安装等待时间也会越长;对于产品本身,意味着下载转化率会越低(因为竞品中,用户有更多机会选择那个体验最好,功能最多,性能最好,包最小的),所以apk的瘦身优化也很重要,本篇博客将讲述apk瘦身的相关内容。

包体分析

在Android Studio工具栏里,打开build–>Analyze APK, 选择要分析的APK包 。

可以看到占用空间的主要是代码、图片、资源和lib和assert文件,主要方向精简代码、压缩图片、去除无用的库、减少asserts里面文件。

使用一套资源

对于绝大对数APP来说,只需要取一套设计图就足够了。鉴于现在分辨率的趋势,建议取720p的资源,放到xhdpi目录。
相对于多套资源,只使用720P的一套资源,在视觉上差别不大,很多大公司的产品也是如此,但却能显著的减少资源占用大小,顺便也能减轻设计师的出图工作量了。

开启minifyEnabled混淆代码

在gradle使用minifyEnabled进行Proguard混淆的配置,可大大减小APP大小:

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选项的清单,标准输出到给定的文件  

压缩

-dontshrink    不压缩输入的类文件
-printusage {filename}
-whyareyoukeeping {class_specification}  

优化

-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}    设置源文件中给定的字符串常量  

开启shrinkResources去除无用资源

在gradle使用shrinkResources去除无用资源,效果非常好。

android {buildTypes {release {shrinkResources true}}
}

清理无用资源

版本迭代过程中,不但有废弃代码冗余,肯定会有无用的图片存在。在build.gradle 里面配置shrinkResources true,在打包的时候会自动清除掉无用的资源,但经过实验发现打出的包并不会,而是会把部分无用资源用更小的东西代替掉。注意,这里的“无用”是指调用图片的所有父级函数最终是废弃代码,而shrinkResources true 只能去除没有任何父函数调用的情况,真正起效果只能通过Android Studio自带的 “Remove Unused Resources”小插件来实现了,直接上图。

更人性化是该查找结果可以“一键删除”。当然,可能图片是经过反射或字符拼接等方式获取,所以这个检测列表也不是全对,删除后很大概率编译失败或部分页面挂死、无图等问题,这个无解,工具还没智能到这个地步,你只能一遍又一遍“编译—解决部分问题—再编译再”,别问我为什么知道。

删除无用的语言资源

大部分应用其实并不需要支持几十种语言的国际化支持。还好强大的gradle支持语言的配置,比如国内应用只支持中文:

android {defaultConfig {resConfigs "zh"}
}

使用tinypng有损压缩

TinyPNG工具只支持上传PNG图片到官网上压缩,然后下载保存,在保持alpha通道的情况下对PNG的压缩可以达到1/3之内,而且用肉眼基本上分辨不出压缩的损失.
Tinypng的官方网站:http://tinypng.com/

使用jpg格式

如果对于非透明的大图,jpg将会比png的大小有显著的优势,虽然不是绝对的,但是通常会减小到一半都不止。
在启动页,活动页等之类的大图展示区采用jpg将是非常明智的选择。

使用webp格式

webp支持透明度,压缩比比jpg更高但显示效果却不输于jpg,官方评测quality参数等于75均衡最佳。
相对于jpg、png,webp作为一种新的图片格式,限于android的支持情况暂时还没用在手机端广泛应用起来。从Android 4.0+开始原生支持,但是不支持包含透明度,直到Android 4.2.1+才支持显示含透明度的webp,使用的时候要特别注意。
官方介绍:https://developers.google.com/speed/webp/docs/precompiled

缩小大图

如果经过上述步骤之后,你的工程里面还有一些大图,考虑是否有必要维持这样的大尺寸,是否能适当的缩小。
事实上,由于设计师出图的原因,我们拿到的很多图片完全可以适当的缩小而对视觉影响是极小的。

删除armable-v7包下的so

基本上armable的so也是兼容armable-v7的,armable-v7a的库会对图形渲染方面有很大的改进,如果没有这方面的要求,可以精简。
这里不排除有极少数设备会Crash,可能和不同的so有一定的关系,请大家务必测试周全后再发布。

删除x86包下的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 = nulluse7zip = trueuseSign = truekeepRoot = false// add <your_application_id>.R.drawable.icon into whitelist.// because the launcher will get thgge icon with his namedef packageName = <your_application_id>whiteList = [//for your iconpackageName + ".R.drawable.icon",//for fabricpackageName + ".R.string.com.crashlytics.*",//for umeng updatepackageName + ".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编译

对于一些库是按照需要动态的加载,可能在某些版本并不需要,但是代码又不方便去除否则会编译不过。
使用provided可以保证代码编译通过,但是实际打包中并不引用此第三方库,实现了控制APP大小的目标。 但是也同时就需要开发者自己判断不引用这个第三方库时就不要执行到相关的代码,避免APP崩溃。

矢量图

矢量图是由点与线组成,和位图不一样,它再放大也能保持清晰度,而且使用矢量图比位图设计方案能节约30~40%的空间,现在谷歌一直在强调扁平化方式,矢量图可很好的契合该设计理念。
—优势
(1)占用存储空间小
(2) 无极拉伸不会出现锯齿,可以照顾不同尺寸的机型
(3)Android Studio自带很多资源,减小UI工作量
—劣势
(1) 只支持5.0及以上系统
(2) 与位图相比多了一层计算,需消耗更多性能
(3) 不支持.9图
(4)不适合表现真实照片和复杂图形,一般使用在简单的icon和动画上

使用着色方案

相信你的工程里也有很多selector文件,也有很多相似的图片只是颜色不同,通过着色方案我们能大大减轻这样的工作量,减少这样的文件。
借助于android support库可实现一个全版本兼容的着色方案,参考代码:DrawableLess.java

在线化素材库

如果你的APP支持素材库(比如聊天表情库)的话,考虑在线加载模式,因为往往素材库都有不小的体积。这一步需要开发者实现在线加载,一方面增加代码的复杂度,一方面提高了APP的流量消耗,建议酌情择。

避免重复库

避免重复库看上去是理所当然的,但是秘密总是藏的很深,一定要当心你引用的第三方库又引用了哪个第三方库,这就很容易出现功能重复的库了,比如使用了两个图片加载库:Glide和Picasso。 通过查看exploded-aar目录和External Libraries或者反编译生成的APK,尽量避免重复库的大小,减小APP大小。

清理第三方库和冗余代码

版本迭代过程中,因为删减功能经常有冗余代码和第三方库留下,这或多或少都会增加包体,这种情况没有捷径,只能每个文件查找,这是苦力活。还有要查看第三方库有没可能精简,比如谷歌分基础、广告和分析包,网络库、supportv4等,这个就具体情况具体分析,不多阐述。

支持插件化

插件化技术支持动态的加载代码和动态的加载资源,把APP的一部分分离出来了,对于业务庞大的项目来说非常有用,极大的分解了APP大小。
因为插件化技术需要一定的技术保障和服务端系统支持,有一定的风险,如无必要(比如一些小型项目,也没什么扩展业务)就不需要了,建议酌情选择。

Facebook的redex优化字节码

redex是facebook发布的一款android字节码的优化工具,需要按照说明文档自行配置一下。

redex input.apk -o output.apk --sign -s <KEYSTORE> -a <KEYALIAS> -p <KEYPASS>

下面我们来看看它的效果,仅redex的话,减小了157k:

下面我们来看看它的效果,仅redex的话,减小了157k:


如果先进行微信混淆,再redex,减小了565k,redex只贡献了10k:

如果先进行redex,在进行微信混淆,减小了711k,redex贡献了157k:

最后一种的效果是最好的,这是很容易解释的,如果最后是redex的重新打包则浪费了前面的7zip压缩,所以为了最优效果要注意顺序。
另外,据反应redex后会有崩溃的现象,这个要留意一下,我这里压缩之后都是可以正常运行的。
详情参考:ReDex

Android优化系列之apk瘦身相关推荐

  1. Android性能优化系列之apk瘦身

    Android性能优化系列之布局优化 Android性能优化系列之内存优化 为什么APK要瘦身.APK越大,在下载安装过程中,他们耗费的流量会越多,安装等待时间也会越长:对于产品本身,意味着下载转化率 ...

  2. Android性能优化(5):APK瘦身优化

    文章目录 1. APK文件结构 2. APK瘦身优化 2.1 优化dex文件大小 2.1.1 Proguard 2.1.2 AndResGuard 2.2 优化资源文件大小 2.2.1 Android ...

  3. Android开发——今日头条APK瘦身之路

    随着版本迭代,功能增加安装包体积也会慢慢增大. 今日头条576版本APK达到了25M,通过一系列的优化,到目前的607版本为12M.本文主要是介绍头条APK瘦身中用到的一些方法. APK分析 既然是要 ...

  4. 深入理解android 包体积优化,给apk瘦身全部技巧

    前言 随着iphone13p最大内存放大到了1T,大内存手机的时代悄然降临,在android里面,三星也有,罗老师几年前说:如果我告诉你们我们在做1T的手机,你们可能以为我疯了. 看看现在,估计未来会 ...

  5. 「Android」 APK瘦身探索

    本文来自尚妆Android团队青峰 发表于尚妆博客 APK瘦身探索 最近几周一直在研究如何为APK瘦身,折腾了很久,是时候写篇博客总结一下了,虽然已经准备了下周一要在客户端周会分享用的PPT:APK瘦 ...

  6. androidstudio打包apk 文件_每天一个小知识——APK瘦身

    唯有美食 不可辜负 温度与风度同在,它虽然地处边角.远离喧嚣,但是到处都满载着精彩,周围弥漫着优雅的闲情逸致. Android性能优化之APK瘦身 面试中面试官常常会问道有关性能优化的问题,而性能优化 ...

  7. Android 性能优化(62)---存检测、卡顿优化、耗电优化、APK瘦身——详解篇

    Android 性能优化,内存检测.卡顿优化.耗电优化.APK瘦身--详解篇 自2008年智能时代开始,Android操作系统一路高歌,10年智能机发展之路,如今 Android 9.0 代号P  都 ...

  8. Android性能优化之APK瘦身最全总结

    Android性能优化之APK瘦身最全总结 随着业务复杂度的逐渐增加,代码.资源也在不断的增加,此时你的APP大小也在增加.从用户层面来说,面对动辄几十兆的APP来说在非WIFI情况下还是会犹豫要不要 ...

  9. Android性能优化之APK瘦身详解(瘦身73%)

    image 公司项目在不断的改版迭代中,代码在不断的累加,终于apk包不负重负了,已经到了八十多M了.可能要换种方式表达,到目前为止没有正真的往外推过,一直在内部执行7天讨论需求,5天代码实现的阶段. ...

最新文章

  1. SQLserver数据库操作帮助类SqlHelper
  2. B站上线!DeepMind加UCL强强联手推出深度学习与强化学习进阶课程(附视频)
  3. 201671010145 2016-2017《Java程序设计》JAVA语言中,异常处理有哪几种方式?
  4. 扩展虚拟机Ubuntu磁盘容量空间
  5. 镜像VirtualBox 下安装 CentOS 7搭建python项目
  6. 深度学习基本概念笔记
  7. java JDK8 学习笔记——第13章 时间与日期
  8. 在线分流框架下的AB Test
  9. C语言中#define的用法
  10. maven 编译出错解决
  11. url指定服务器是什么意思,URL是什么意思?网页的URL是什么意思?
  12. Tensorflow1.7+cuda9.0+cudnn7.0中的各种意(da)外(keng)
  13. iota 的 优点与吐槽
  14. 【MySQL】创建数据表
  15. matlab开环调速,直流电动机开环调速MATLAB系统仿真
  16. IoT技术概览(postscapes)
  17. CMDN CLUB第14场:小米与友盟专家详解Android开发:
  18. [讨论]去掉office正版提醒
  19. C语言——自定义类型(结构体,枚举,联合体,位段)
  20. Landsat5数据下载中国地区1991年

热门文章

  1. 全局处理ajax请求时session超时
  2. Exploiting “BadIRET” vulnerability (CVE-2014-9322, Linux kernel privilege escalation)
  3. Tomcat 6 --- JNDI详解
  4. Signalr2_消息弹窗
  5. Effective JavaScript Item 33 让构造函数不再依赖newkeyword
  6. Vue-Cleave - 在Vue中使用CleaveJS格式化你的输入内容
  7. webstom设置和monokia配色方案
  8. 思科设备路由器间IPsec ×××实现私网之间通信实战
  9. 如何修改Win7开机登陆界面背景图片
  10. sql range 范围内查询