汇总:Android小白成长之路_知识体系汇总【持续更新中…】
想要对包体积大小进行优化,首先需要了解apk的组成,apk实际上是一个压缩包,把apk拖进Android Studio中可以看到如下结构:
Dalvik/ART
虚拟机理解的 DEX
格式的 class
文件CERT.SF
和 CERT.RSA
签名文件, 以及MANIFEST.MF
清单文
armeabi
, armeabi-v7a
, arm64-v8a
, x86
, x86_64
这些分类等等,通常占着大量的空间,急需优化mp3
文件、lottie
动画的图片资源和json
文件无效代码包括:
操作方法:使用Android Studio
的Analyze -> Inspect Code
进行代码检测,可以查找未使用的代码,对于重复工具类和已下架功能代码等需要手动检查
优化效果:无效代码体积本身占比不大,优化很小
注意事项:
Google
在 Android Studio 3.1
版本之后使用D8
作为版本开发工具默认的Dex
编译器,D8
的 优化效果总的来说可以归结为如下四点:
操作方法:在Android Studio 3.0
需要主动在gradle.properties
文件中新增:
android.enableD8 = true
Android Studio 3.1
或之后的版本D8
将会被作为默认的Dex
编译器
优化效果:Dex略微变小
参考链接:新一代Dex编译器:D8
Proguard
是一个免费的 Java 类文件压缩、优化、混淆、预先校验的工具,主要作用可以概括为 两点:
操作方法:
buildTypes {
release {
// 1、是否进行混淆
minifyEnabled true
// 2、开启zipAlign可以让安装包中的资源按4字节对齐,这样可以减少应用在运行时的内存消耗
zipAlignEnabled true
// 3、移除无用的resource文件:当ProGuard 把部分无用代码移除的时候,
// 这些代码所引用的资源也会被标记为无用资源,然后
// 系统通过资源压缩功能将它们移除。
// 需要注意的是目前资源压缩器目前不会移除values/文件夹中
// 定义的资源(例如字符串、尺寸、样式和颜色)
// 开启后,Android构建工具会通过ResourceUsageAnalyzer来检查
// 哪些资源是无用的,当检查到无用的资源时会把该资源替换
// 成预定义的版本。主要是针对.png、.9.png、.xml提供了
// TINY_PNG、TINY_9PNG、TINY_XML这3个byte数组的预定义版本。
// 资源压缩工具默认是采用安全压缩模式来运行,可以通过开启严格压缩模式来达到更好的瘦身效果。
shrinkResources true
// 4、混淆文件的位置,其中 proguard-android.txt 为sdk默认的混淆配置,
// 它的位置位于android-sdk/tools/proguard/proguard-android.txt,
// 此外,proguard-android-optimize.txt 也为sdk默认的混淆配置,
// 但是它默认打开了优化开关。并且,我们可在配置混淆文件将android.util.Log置为无效代码,
// 以去除apk中打印日志的代码。而 proguard-rules.pro 是该模块下的混淆配置。
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
优化效果:如果全部功能开启,优化较好
参考链接:混淆工具:Proguard
Google
在Android Studio 3.2
中引入R8
作为 ProGuard
的替代工具,用于代码的压缩(shrinking)和混淆(obfuscation),ProGuard
和R8
都应用了基本名称混淆:它们都使用简短,无意义的名称重命名类,字段和方法。他们还可以删除调试属性。但是,R8
在inline
内联容器类中更有效,并且在删除未使用的类,字段和方法上则更具侵略性。例如,R8
本身集成在ProGuard V6.1.1
版本中,在压缩 apk
的大小方面,与 ProGuard
的 8.5% 相比,使用 R8 apk 尺寸减小了约 10%。并且,随着 Kotlin
现在成为 Android 的第一语言,R8 进行了 ProGuard
尚未提供的一些 Kotlin
的特定的优化。
操作方法:如果我们当前使用的是Android Studio 3.4
或 Android Gradle
插件3.4.0
及其更高版本,R8 会作为默认编译器。否则,我们 必须要在 gradle.properties
中配置如下代码让 App 的混淆去支持 R8:
android.enableR8=true
android.enableR8.libraries=true
优化效果:Proguard
的升级版本,优化较好
APK 的资源主要包括图片、XML,由于版本更新迭代,会遗留很多旧版本使用但新版本不再使用的资源文件,这些资源文件也会占用空间,需要删除
操作方法:选中菜单项Refactor
,然后点击Remove Unused Resource => preview
可以预览找到的无用资源,点击 Do Refactor
可以去除冗余资源
优化效果:无用资源越多优化越好
注意事项:可能需要手动再次确认资源真实未使用,不能使用一键删除,否则会导致某些特殊情况下使用的资源找不到
Proguard
混淆自带的资源压缩
操作方法:在Proguard
混淆中开启
shrinkResources true
优化效果:优化效果一般
WebP 是 Google 的一种可以同时提供有损压缩(像JPEG
一样)和透明度(像 PNG
一样)的图片文件格式,不过与JPEG
或PNG
相比,这种格式可以提供更好的压缩。Android 4.0
(API 级别 14)及更高版本支持有损 WebP
图片,Android 4.3
(API 级别 18)及更高版本支持无损且透明的 WebP
图片
操作方法:在Android Studio
中右键点击某个图片文件或包含一些图片文件的文件夹,然后点击 Convert to WebP
优化效果:如果png
没压缩过,优化效果很大,如果png
已经压缩过了,也依然有一定的优化作用
注意事项:
Android 4.3
及更高版本支持无损和透明的webp
图片,因此minSdkVersion
必须为18或者更高9-patch
文件无法转换为WebP
图片,转换器工具会自动跳过9-patch
图片Google play
不允许app
图标使用非png
格式,因此不能对app图标进行转换TinyPNG
使用智能有损压缩技术将PNG
文件的文件大小降低。 通过选择性的减少图片中的颜色,只需要很少的字节数就能保存数据。 对视觉的影响几乎不可见,但是在文件大小上有非常大的差别
操作方法:
Android Studio
下载TinyPng Image Optimizer
插件png
图片,右键选中Optimize Image Size
Optimize
即可优化效果:较大,但比不上转webp
参考链接:TinyPng
在功能迭代后,会有一些so库不再使用,必须尽快移除,因为so占体积比很大,特别是分多个abi的情况下
优化效果:so越大,优化效果越大
提取so库功能,精简so库中无用代码,可以进一步减小so库的大小
优化效果:一般
目前,Android 一共 支持7种不同类型的 CPU 架构,比如常见的 armeabi、armeabi-v7a、X86
等等。理论上来说,对应架构的 CPU 它的执行效率是最高的,但是这样会导致 在lib
目录下会多存放了各个平台架构的 So 文件,所以 App 的体积自然也就更大了,因此需要对lib目录进行精简。一般情况下,应用都不需要用到 neon
指令集,我们只需留下 armeabi
目录就可以了。因为armeabi
目录下的 so 可以兼容别的平台上的 so,相当于是一个万金油,都可以使用。但是,这样 别的平台使用时性能上就会有所损耗,失去了对特定平台的优化,如果不考虑性能,可以直接配置:
defaultConfig {
ndk {
abiFilters "armeabi"
}
}
但这样做会影响性能,所以可以考虑一个折中的方案:对于性能敏感的模块,它使用到的 so,即使是属于其他abi
,也都放在 armeabi
目录当中随着 Apk 发出去,然后在代码中来判断一下当前设备所属的 CPU 类型,根据不同设备 CPU 类型来加载对应架构的 So 文件:
String abi = "";
// 获取当前手机的CPU架构类型
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
abi = Buildl.CPU_ABI;
} else {
abi = Build.SUPPORTED_ABIS[0];
}
if (TextUtils.equals(abi, "x86")) {
// 加载特定平台的So
} else {
// 正常加载
}
滴滴在 Github 上开源了一个 Android App 的质量优化工具Booster
,Booster
是一款专门为移动应用设计的易用、轻量级且可扩展的质量优化框架,其目标主要是为了解决随着 APP 复杂度的提升而带来的性能、稳定性、包体积等一系列质量问题。Booster 提供了性能检测、多线程优化、资源索引内联、资源去冗余、资源压缩、系统 Bug 修复等一系列功能模块,可以使得稳定性能够提升 15% ~ 25%,包体积可以减小 1MB ~ 10MB。只为了优化包体积大小,可以选择性集成部分功能
操作方法:
在项目根目录的build.gradle
中配置:
buildscript {
ext.booster_version = '3.1.0'
repositories {
google()
mavenCentral()
}
dependencies {
//booster基础插件
classpath "com.didiglobal.booster:booster-gradle-plugin:$booster_version"
//采用 cwebp 对资源进行压缩
classpath "com.didiglobal.booster:booster-task-compression-cwebp:$booster_version"
//ap_ 文件压缩
classpath "com.didiglobal.booster:booster-task-compression-processed- res:$booster_version"
//去冗余资源
classpath "com.didiglobal.booster:booster-task-resource-deredundancy:$booster_version"
//资源索引内联
classpath "com.didiglobal.booster:booster-transform-r-inline:$booster_version"
}
}
}
在主工程模块的build.gradle
中引入插件:
apply plugin: 'com.didiglobal.booster'
在gradle.properties
中配置:
android.precompileDependenciesResources=false
优化效果:很大,建议使用
注意事项:采用这个插件会增加编译时间,因此在调试开发阶段不应该开启,可以添加以下判断,只在打publish包的时候才使用:
ext.isPublish = gradle.startParameter.taskNames.any { it.contains('publish') || it.contains('Publish') }
classpath "com.didiglobal.booster:booster-gradle-plugin:$boosterVersion"
if (isPublish) {
classpath "com.didiglobal.booster:booster-task-compression-cwebp:$boosterVersion"
classpath "com.didiglobal.booster:booster-task-compression-processed-res:$boosterVersion"
classpath "com.didiglobal.booster:booster-task-resource-deredundancy:$boosterVersion"
classpath "com.didiglobal.booster:booster-transform-r-inline:$boosterVersion"
}
参考链接:质量优化框架:booster
Android App Bundle
是一种发布格式,其中包含应用的所有经过编译的代码和资源,它会将 APK 生成及签名交由 Google Play 来完成。Google Play 会使用 app bundle 针对每种设备配置生成并提供经过优化的 APK,因此只会下载特定设备所需的代码和资源来运行应用。不必再构建、签署和管理多个 APK 来优化对不同设备的支持,而用户也可以获得更小且更优化的下载文件包,这在Google play上架的应用来说是非常有效的
操作方法:
Android Studio 3,2
或以上版本Build
菜单,右键选择Build Bundles(s)/Apk(s)
,然后点击Build Bundle(s)
Generate Signed Bundle or Apk
对生成的aab
文件进行签名,需要进行秘钥的配置buildtool
进行安装测试,或者把aab文件上传到google play
控制台的测试通道进行测试优化效果:非常大,Google play上架的app极力推荐
注意事项:
Android App Bundle
才能在 Google Play 中发布参考链接:Android App Bundle
以下优化方式存在各种各样的问题,看自己情况使用
XZ Utils
是具有高压缩率的免费通用数据压缩软件。XZ Utils
是为类似POSIX
的系统编写的,但也可以在某些非POSIX
系统上使用。XZ Utils
是LZMA Utils
的后继产品。XZ Utils
压缩代码的核心基于LZMA SDK
,但是已经对其进行了大量修改以适合XZ Utils
。当前,主要压缩算法是LZMA2
,它在.xz
容器格式内使用。对于典型文件,XZ Utils
的输出比gzip
小30%,比bzip2
小15%
存在的问题
参考链接:XZ Utils
为了能提供内部类和其外部类直接访问对方的私有成员的能力,又不违反封装性要求,Java 编译器在编译过程中自动生成 package 可见性的静态 access$xxx
方法,并且在需要访问对方私有成员的地方改为调用对应的 access 方法。在开发过程中需要注意在可能产生 access 方法的情况下适当调整,比如去掉 private,改为 package 可见性,也可以使用ASM
或者ByteX
在编译时删除生成的 access 方法。
存在的问题:效果很小但使用相对麻烦
AndResGuard
是微信团队开源出来的一个注重减小Res包大小的工具,可以直接对Apk进行处理得到处理后的Apk文件。原理类似Java Proguard
,但是只针对资源。他会将原本冗长的资源路径变短,例如将res/drawable/wechat
变为r/d/a
。AndResGuard
不涉及编译过程,只需输入一个apk(无论签名与否,debug版,release版均可,在处理过程中会直接将原签名删除),可得到一个实现资源混淆后的apk(若在配置文件中输入签名信息,可自动重签名并对齐,得到可直接发布的apk)以及对应资源ID的mapping文件
apply plugin: 'AndResGuard'
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.20'
}
}
andResGuard {
// mappingFile = file("./resource_mapping.txt")
mappingFile = null
use7zip = true
useSign = true
// 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字
keepRoot = false
// 设置这个值,会把arsc name列混淆成相同的名字,减少string常量池的大小
fixedResName = "arg"
// 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源
mergeDuplicatedRes = true
whiteList = [
// for your icon
"R.drawable.icon",
// for fabric
"R.string.com.crashlytics.*",
// for google-services
"R.string.google_app_id",
"R.string.gcm_defaultSenderId",
"R.string.default_web_client_id",
"R.string.ga_trackingId",
"R.string.firebase_database_url",
"R.string.google_api_key",
"R.string.google_crash_reporting_api_key"
]
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
]
sevenzip {
artifact = 'com.tencent.mm:SevenZip:1.2.20'
//path = "/usr/local/bin/7za"
}
/**
* 可选: 如果不设置则会默认覆盖assemble输出的apk
**/
// finalApkBackupPath = "${project.rootDir}/final.apk"
/**
* 可选: 指定v1签名时生成jar文件的摘要算法
* 默认值为“SHA-1”
**/
// digestalg = "SHA-256"
}
参考链接:Apk混淆工具:AndResGuard
节跳动抖音技术团队开源的一款针对 .aab
文件的资源混淆工具,也就是使用app bundle
打包的应用,由于 .aab
和 .apk
文件结构的差异,AndResGuard 的资源混淆方案是不适用于 AAB 的,需要使用它的另一个版本,也就是AabResGuard,使用方式:
在 build.gradle(root project)
中进行配置:
buildscript {
repositories {
mavenCentral()
jcenter()
google()
}
dependencies {
classpath "com.bytedance.android:aabresguard-plugin:0.1.0"
}
}
在 build.gradle(application)
中配置
apply plugin: "com.bytedance.android.aabResGuard"
aabResGuard {
mappingFile = file("mapping.txt").toPath() // 用于增量混淆的 mapping 文件
whiteList = [ // 白名单规则
"*.R.raw.*",
"*.R.drawable.icon"
]
obfuscatedBundleFileName = "duplicated-app.aab" // 混淆后的文件名称,必须以 `.aab` 结尾
mergeDuplicatedRes = true // 是否允许去除重复资源
enableFilterFiles = true // 是否允许过滤文件
filterList = [ // 文件过滤规则
"*/arm64-v8a/*",
"META-INF/*"
]
enableFilterStrings = false // 过滤文案
unusedStringPath = file("unused.txt").toPath() // 过滤文案列表路径 默认在mapping同目录查找
languageWhiteList = ["en", "zh"] // 保留en,en-xx,zh,zh-xx等语言,其余均删除
参考链接:Aab混淆工具:AabResGuard
ByteX
是字节跳动抖音团队开发的一个基于gradle transform api
和ASM
的字节码插件平台。目前集成了若干个字节码插件,每个插件完全独立,既可以脱离ByteX
这个宿主而独立存在,又可以自动集成到宿主和其它插件一起整合为一个单独的Transform
。插件和插件之间,宿主和插件之间的代码是完全解耦的(有点像组件化),这使得ByteX
在代码上拥有很好的可拓展性,新插件的开发将会变得更加简单高效
buildscript {
ext.plugin_version="0.2.6"
repositories {
google()
jcenter()
}
dependencies {
classpath "com.bytedance.android.byteX:base-plugin:${plugin_version}"
// Add bytex plugins' dependencies on demand. 按需添加插件依赖
classpath "com.bytedance.android.byteX:refer-check-plugin:${plugin_version}"
// ...
}
}
apply plugin: 'com.android.application'
// apply ByteX宿主
apply plugin: 'bytex'
ByteX {
enable true
enableInDebug false
logLevel "DEBUG"
}
// 按需apply bytex 插件
apply plugin: 'bytex.refer_check'
// ...
已集成的插件
Log.d
)存在的问题:
参考链接:ByteX
根据 App 目前所支持的语言版本去选用合适的语言资源和图片大小
android {
...
defaultConfig {
...
resConfigs "zh", "zh-rCN"
resConfigs "nodpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
}
...
}
存在问题:优化不大,并且可能会导致适配兼容出现问题
将一些图片资源放在服务器,然后 结合图片预加载 的技术手段,这些 既可以满足产品的需要,同时可以减小包大小
存在问题:用户网络不好的时候体验不佳
Native Library
同 Dex
一样,也可以使用XZ Utils
进行压缩,对于 Native Library
的压缩,我们 只需要去加载启动过程相关的Library
,而其它的都可以在应用首次启动时进行解压,并且,压缩效果与 Dex
压缩的效果是相似的
存在问题:和压缩Dex一样,对应用启动时间影响较大
将部分 So 文件使用动态下发的形式进行加载,也就是在业务代码操作之前,可以先从服务器下载下来 So,接下来再使用
存在问题:用户网络不好时体验不佳
将部分 So 文件使用动态下发的形式进行加载,也就是在业务代码操作之前,可以先从服务器下载下来 So,接下来再使用
存在问题:用户网络不好时体验不佳
根据对各种方法的分析,筛选出较为实用和常用的方法如下:
proguard
混淆D8
和R8
webp
格式或TinyPng
压缩png
图片booster
插件优化Android App Bundle
方式打包备选方法: