随着业务复杂度的逐渐增长,代码、资源也在不断的增长,此时你的APP大小也在增长。从用户层面来讲,面对动辄几十兆的APP来讲在非WIFI状况下仍是会犹豫要不要下载,不下载你就可能所以失去了一个用户。从公司层面来说,流量就是钱,减小APP的大小就显得尤其重要。从开发者层面上来说,你掌握了这个手艺也会略显逼格满满。javascript
废话很少说了,开始正题。php
知己知彼,方能百战不殆。了解应用程序APK的结构对于咱们来讲颇有帮助。APK文件由一个ZIP存档组成,其中包含组成应用程序的全部文件。这些文件包括Java类文件,资源文件和包含编译资源的文件。java
APK包含如下目录:android
通常来说APK结构中比较大的部分通常是classes.dex、lib、res、assets这些文件或者目录。因此接下来将会针对这四种状况进行讲解。安全
另外,咱们经过APK Analyser 能够分析 APK;性能优化
classes.dex 包含了全部 Java 代码。当你编译你的应用时,gradle 会将你的全部模块里的 .class 文件转换成 .dex 文件并将这些文件合成一个 classes.dex 文件。bash
单个的 classes.dex 文件能够容纳大约 64K 方法。若是你达到了这个限制,你必需要在你的工程中启用 multidexing。这将会建立另外一个 classes1.dex 文件去存储剩下的方法。因此 classes.dex 文件数目由你的方法数而定。网络
随着业务的频繁变动以及复杂度的增长,咱们每每会使用第三方Libaray,有时候咱们可能仅仅用到了不多一部分的功能,这个时候就须要慎重考虑彻底引用。从个人开发经验上来说,宁愿参照本身去实现,也不肯意多引入一个第三方库。架构
一个枚举能够为您的应用程序的classes.dex文件添加大约1.0到1.4 KB的大小 。这些添加能够快速累积到复杂系统或共享库。若是可能,请考虑使用@IntDef注释,这种类型转换保留了枚举的全部类型安全优点。app
下面这段来自 build.gradle 文件的代码用于为发布构建启用代码压缩:
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
...
}
复制代码
除了 minifyEnabled 属性外,还有用于定义 ProGuard 规则的 proguardFiles 属性:
getDefaultProguardFile('proguard-android.txt') 方法可从 Android SDK tools/proguard/ 文件夹获取默认的 ProGuard 设置。
提示:要想作进一步的代码压缩,请尝试使用位于同一位置的 proguard-android-optimize.txt 文件。它包括相同的 ProGuard 规则,但还包括其余在字节码一级(方法内和方法间)执行分析的优化,以进一步减少 APK 大小和帮助提升其运行速度。
proguard-rules.pro 文件用于添加自定义 ProGuard 规则。默认状况下,该文件位于模块根目录(build.gradle 文件旁)。
题外话
res/raw和assets的相同点:
二者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。
res/raw和assets的不一样点:
3.1 图片资源优化策略
格式压缩;使用TinyPng或者Guetzli进行压缩。
使用WebP文件格式
定位Android 3.2(API级别13)或更高级别时 ,您也可使用WebP文件格式来制做图像,而不是使用PNG或JPEG文件。WebP格式提供有损压缩(如JPEG)以及透明度(如PNG),但能够提供比JPEG或PNG更好的压缩。
Android 4.0 (API level 14) 支持有损压缩的WebP格式,Android 4.3 (API level 18) 开始支持无损透明WebP图像。
看下图:
压缩效率极高,仅为PNG格式的12%。惊喜不惊喜。。。
使用矢量图形
您可使用矢量图形来建立与分辨率无关的图标和其余可伸缩媒体。使用这些图形能够大大减小您的APK足迹。矢量图像在Android中表示为VectorDrawable对象。经过一个VectorDrawable对象,一个100字节的文件能够生成一个与屏幕尺寸一致的清晰图像。
可是,系统渲染每一个 VectorDrawable对象须要很长时间,而较大的图像须要更长的时间才能显示在屏幕上。所以,只有在显示小图像时才考虑使用这些矢量图形。
其它策略
有时候咱们可能对一张图片进行重复利用,好比一张图片仅仅是总体颜色的变换可使用setColorFilter或者tint。尽可能减小使用帧动画,那但是一堆图片呀。
3.2 压缩资源
要启用资源压缩,请在 build.gradle 文件中将 shrinkResources 属性设置为 true。
android {
...
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
复制代码
资源压缩器目前不会移除 values/ 文件夹中定义的资源(例如字符串、尺寸、样式和颜色)。这是由于 Android 资源打包工具 (AAPT) 不容许 Gradle 插件为资源指定预约义版本。
同时,咱们也能够指定哪些资源能够保留下来。
例如,将下边的代码保存在 res/raw/keep.xml。构建不会将该文件打包到 APK 之中。
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*" tools:discard="@layout/unused2" />
复制代码
resources有如下属性:
safe和strict的优化策略:
safe能够简单理解为安全模式,它会尽最大努力检查代码中可能会使用到的资源进行保留,避免运行时错误。
若是你的代码调用 Resources.getIdentifier(),这就表示你的代码将根据动态生成的字符串查询资源名称。当你执行这一调用时,默认状况下资源压缩器会采起防护性行为,将全部具备匹配名称格式的资源标记为可能已使用,没法移除。
String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());
复制代码
img_ 前缀的资源标记为已使用。
在strict模式下,img_前缀的资源会作未使用的处理,所以你须要使用tools:keep手动进行已使用标识。
移除未使用的备用资源
咱们知道google给咱们的apk提供了国际化支持,如适应不一样的屏幕分辨率的drawable资源,还有适应不一样语言的字符串资源等等,可是在不少状况下咱们只须要一些指定分辨率和语言的资源就能够了,这个时候咱们可使用resConfigs方法来配置。
defaultConfig {
// 对于国际化支持只打包中文资源,
resConfigs "zh-rCN"
}
复制代码
这里咱们主要讲一下lib中动态连接库的优化策略,也就是SO文件。若是你有NDK的开发经验可能会更容易理解一些。
为了支持不一样指令集的状况,应用可能会包含armeabi、armeabi-v7a、x86的SO文件等。
目前主流的机型都是支持armeabi-v7a的,而且armeabi-v7a兼容armeabi。因此在通常的开发中咱们只须要使用armeabi-v7a 进行ABI支持。
有些SO库能够采用网络下载,把负担放到用户安装完应用以后。对于哪些SO文件能够放到网络中加载,还须要看具体业务状况。
题外话,若是运行时找不到SO的话,会致使应用崩溃。
java.lang.UnsatisfiedLinkError: Couldn't load stlport_shared
from loader dalvik.system.PathClassLoader: findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:365)
at java.lang.System.loadLibrary(System.java:535)
at com.your.app.NativeClass.<clinit>(Native.java:16)
... 63 more
Caused by: java.lang.UnsatisfiedLinkError: Library stlport_shared not found
at java.lang.Runtime.loadLibrary(Runtime.java:461)
at java.lang.System.loadLibrary(System.java:557)
at com.your.app.NativeClass.<clinit>(Native.java:16)
... 5 more
复制代码
不过也是有办法应对的,能够参见这个开源项目;ReLinker
5.1.全方位性能调优技术体系;
5.2.Android架构师脑图;
5.3.全套高级架构视频;
正在整理一套完整的Android架构视频,免费分享。目前还在更新中,欢迎关注谢谢支持
(包括java基础与原理,自定义控件、NDK、架构设计、混合式开发(Flutter,Weex)、性能优化、完整商业项目开发等技术体系)