Android性能优化系列之apk瘦身

时间:2023-03-08 22:45:03
Android性能优化系列之apk瘦身

Android性能优化系列之布局优化

Android性能优化系列之内存优化

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

包体分析

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

Android性能优化系列之apk瘦身

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjEyNDQzOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

能够看到占用空间的主要是代码、图片、资源和lib和assert文件。主要方向精简代码、压缩图片、去除没用的库、降低asserts里面文件。

使用一套资源

对于绝大对数APP来说,仅仅须要取一套设计图就足够了。鉴于如今分辨率的趋势。建议取720p的资源,放到xhdpi文件夹。

相对于多套资源,仅仅使用720P的一套资源,在视觉上区别不大,非常多大公司的产品也是如此。但却能显著的降低资源占用大小,顺便也能减轻设计师的出图工作量了。

注意。这里不是说把不是xhdpi的文件夹都删除,而是强调保留一套设计资源就够了。

开启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”小插件来实现了,直接上图。

Android性能优化系列之apk瘦身

更人性化是该查找结果能够“一键删除”。

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

删除没用的语言资源

大部分应用其实并不须要支持几十种语言的国际化支持。还好强大的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

缩小大图

假设经过上述步骤之后。你的project里面另一些大图,考虑是否有必要维持这种大尺寸,能否适当的缩小。

其实,由于设计师出图的原因,我们拿到的非常多图片全然能够适当的缩小而对视觉影响是极小的。

覆盖第三库里的大图

有些第三库里引用了一些大图可是实际上并不会被我们用到,就能够考虑用1x1的透明图片覆盖。

你可能会有点不舒服,由于你的drawable下居然包括了一些莫名其妙的名称的1x1图片…

删除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 = 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编译

对于一些库是依照须要动态的载入,可能在某些版本号并不须要,可是代码又不方便去除否则会编译只是。

使用provided能够保证代码编译通过,可是实际打包中并不引用此第三方库,实现了控制APP大小的目标。

可是也同一时候就须要开发人员自己推断不引用这个第三方库时就不要执行到相关的代码,避免APP崩溃。

矢量图

矢量图是由点与线组成,和位图不一样,它再放大也能保持清晰度,并且使用矢量图比位图设计方案能节约30~40%的空间,如今谷歌一直在强调扁平化方式,矢量图可非常好的契合该设计理念。

—优势

(1)占用存储空间小

(2) 无极拉伸不会出现锯齿,能够照应不同尺寸的机型

(3)Android Studio自带非常多资源。减小UI工作量

—劣势

(1) 仅仅支持5.0及以上系统

(2) 与位图相比多了一层计算,需消耗很多其它性能

(3) 不支持.9图

(4)不适合表现真实照片和复杂图形。一般使用在简单的icon和动画上

使用shape背景

特别是在扁平化盛行的当下。非常多纯色的渐变的圆角的图片都能够用shape实现。代码灵活可控,省去了大量的背景图片。

使用着色方案

相信你的project里也有非常多selector文件。也有非常多类似的图片仅仅是颜色不同,通过着色方案我们能大大减轻这种工作量,降低这种文件。

借助于android support库可实现一个全版本号兼容的着色方案。參考代码:DrawableLess.java

在线化素材库

假设你的APP支持素材库(比方聊天表情库)的话,考虑在线载入模式,由于往往素材库都有不小的体积。

这一步须要开发人员实如今线载入,一方面添加代码的复杂度,一方面提高了APP的流量消耗,建议酌情选择。

避免反复库

避免反复库看上去是理所当然的。可是秘密总是藏的非常深,一定要当心你引用的第三方库又引用了哪个第三方库,这就非常easy出现功能反复的库了。比方使用了两个图片载入库: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:

Android性能优化系列之apk瘦身

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

Android性能优化系列之apk瘦身

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjEyNDQzOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

假设先进行微信混淆。再redex,减小了565k,redex仅仅贡献了10k:

Android性能优化系列之apk瘦身

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjEyNDQzOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

假设先进行redex,在进行微信混淆,减小了711k。redex贡献了157k:

Android性能优化系列之apk瘦身

最后一种的效果是最好的,这是非常easy解释的,假设最后是redex的又一次打包则浪费了前面的7zip压缩,所以为了最优效果要注意顺序。

另外,据反应redex后会有崩溃的现象。这个要留意一下,我这里压缩之后都是能够正常执行的。

详情參考:ReDex