Android优化系列之apk瘦身

概述

为什么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 = 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和动画上

使用着色方案

相信你的工程里也有很多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

时间: 2024-10-03 19:45:10

Android优化系列之apk瘦身的相关文章

Android APK瘦身实践

因为推广的需要,公司需要把APK的大小再"减小"一下,4M以内! 当达到4M以内之后,公司建议说,能否再压压?2M如何? 瘦身前 因为平时就考虑到大小的限制,所以很多工作已经做过了,如下列举现在的状态: 7.3M(Debug版本)和6.5M(Release版本) 开启minifyEnabled 开启shrinkResources 已经去除不相关的大型库 图片和代码已经经历过粗略的一轮清理 开始魔鬼瘦身 1. tinypng有损压缩 android打包本身会对png进行无损压缩,不信大家

APK瘦身记,如何实现高达53%的压缩效果

APK瘦身记,如何实现高达53%的压缩效果       1.我是怎么思考这件事情的 APK是Android系统安装包的文件格式,关于这个话题其实是一个老生常谈的题目,不论是公司内部,还是外部网络,前人前辈已经总结出很多方法和规律.不过随着移动端技术近两年的飞速发展,一些新的思维方式和优化方法也逐渐涌现和成熟起来.笔者在实践过程中踩过一些坑,收获了一些经验,在这里做个思考和总结,所以随笔给大家,希望对大家从事相关工作的时候有所帮助和参考,同时也是抛砖引玉,希望大家共同探讨这个开放性的话题. 关于为

扇贝张志博--APK瘦身的实践与演进

[51CTO.com原创稿件]扇贝是一个全面有效提升英语的移动互联网学习平台,有包括单词.听力.口语.新闻.阅读.炼句在内的六大应用,是目前国内唯一能让用户在移动端完成英语学习整个一套闭环的学习系统. 为什么要做APK瘦身? 一个很现实的事情是,到上个月底有23.49%用户使用移动网络使用App,其中有4.09%用户还在使用2G网络,这是一个很可怕的数字,因为到今天为止仍在使用Android2.3的用户已经是1%甚至连1%都不到的在网用户量,然而使用2G网络用户还有4.09%.因为现在用户使用移

基于WebSphere Commerce的电子商务应用性能优化(3) 网络流量瘦身建议

网络流量瘦身建议 浏览器端用户所感受到的响应时间受很多因素影响,最主要的来的三个方面: 服务器端的内容生成时间,受服务器端硬件计算能力和服务器的应用程序性能影响 网络上传输数据的时间,受网络带宽和所传输数据的大小影响 客户端渲染时间,受客户端浏览器性能和客户端程序性能影响 服务器端和客户端的性能我们在本系列文章的其他部分中有讨论.本部分着重讨论如何减少网络传输时间 .用户与服务器的交互不可避免要在网络上传输数据.尤其是近年来 WEB2.0 等技术的采用,越来越多的交互 和渲染工作转移到浏览器端进

通过Gradle为APK瘦身

本文选自<Gradle for Android 中文版>,将研究如何设置Gradle 构建配置文件中的几个属性,以缩小APK 文件. ProGuard ProGuard 是一个Java 工具,其不仅可以缩减APK 文件大小,还可以在编译期优化.混淆和预校验你的代码.其通过你应用的所有代码路径,来找到未被使用的代码,并将其删除. ProGuard 还会重命名你的类和字段.这一过程将保留应用的踪迹,让反编译工程师更加难以读懂代码. 在Gradle 的Android 插件中,其构建类型下面有一个叫作

Android优化系列一: 日志清理

简介 在Android应用开发过程中,通过Log类输出日志是一种很重要的调试手段.大家对于Log类的使用,一般会形成几点共识: 1. 在Debug模式下打印日志,在Release模式下不打印日志 1. 避免滥用Log类进行输出日志.因为这样可能造成日志刷屏,淹没真正有用的日志. 1. 封装Log类,以提供同时输出日志到文件等功能 具体细化为以下几点建议: 1. 禁用System.out.printlnAndroid应用中,一般通过封装过的Log类来输出日志,方便控制.而System.out.pr

Javascript优化技巧(文件瘦身篇)_javascript技巧

最近一直在研究 Javascript 相关的技术.在<Javascript 高级程序设计>有篇章节着重阐述了优化 Javascript 代码的重要性.相信有很多的 Javascript 开发人员在开发的同时或多或少的会接触到此类的问题. 在大部分情况下,代码的优化并不是实际开发中所需要着重的部分.但是一旦代码完成了以后,开发者总是期待自己的代码能够越短越高效越好.结合从书中获得的知识以及本人实际开发过程中的经验,下面说明本人所采取的一些花招(也算是照本宣科一下). 前言 相比脚本语言,编译型的

我的Android进阶之旅------&amp;gt;Android APP终极瘦身指南

首先声明,下面文字转载于: APK瘦身实践 http://www.jayfeng.com/2015/12/29/APK%E7%98%A6%E8%BA%AB%E5%AE%9E%E8%B7%B5/ APP终极瘦身指南 http://www.jayfeng.com/2016/03/01/Android-APP%E7%BB%88%E6%9E%81%E7%98%A6%E8%BA%AB%E6%8C%87%E5%8D%97/                                           

Android应用瘦身,从18MB到12.5MB

开篇语 前阵子老大交给了我一个任务,主要是帮我们开发的直播应用做 Android 端的安装包瘦身,花了大概一周的时间把安装包从 18MB 减小到了 12.5MB.原本完全可以优化到 10MB 之下,但由于其他原因的限制,所以目前阶段只到 12.5MB 为止.在此记录一下优化的思路和用到的工具,方便自己以后 Review ,有需要的童鞋也可供参考. 瘦身的目的 从目的导向来看,我们是不会无缘无故去做一件事情的,那我们对应用瘦身的目的是为了什么?答案是:提高下载转化率.什么是下载转化率?举个栗子:你