一、瘦身的目的
APK 瘦身是通过技术手段减少安装包体积的优化过程,目的是:
- 提升用户体验:加快下载速度,降低安装失败率(尤其在网络差或存储不足的设备上)。
- 降低分发成本:减少应用商店流量消耗和服务器存储压力。
二、APK 中可以瘦身的模块
1. 代码优化
- ProGuard/R8:混淆、删除未使用的代码(如废弃功能、测试代码)。
- D8 编译器:优化字节码,减少生成的 DEX 文件体积。
2. 资源优化
- 删除无用资源:
shrinkResources true
自动移除未引用的资源。 - 资源压缩:
- 图片转 WebP/AVIF(比 PNG 小 30% 以上)。
- 矢量图替代位图(适用于简单图标)。
3. so 库优化
- 仅保留必要架构:比如只支持
arm64-v8a
(覆盖 95% 以上设备),放弃armeabi
。
三、APK结构
AndroidManifest.xml | 应用的全局配置(包名、权限、组件声明、SDK 版本要求等),二进制格式。 | 删除冗余权限或 uses-feature 声明,避免过度声明硬件支持。 |
---|---|---|
classes.dex | 包含 Java/Kotlin 代码编译后的 DEX 字节码文件(可能多个,如 classes2.dex )。 | 通过 ProGuard 移除无用代码,D8/R8 优化字节码,减少 DEX 数量和体积。 |
resources.arsc | 编译后的资源索引表(资源 ID、类型、路径映射)。 | 压缩资源路径名(混淆),删除未使用的语言或分辨率配置。 |
res/ | 存放编译后的资源文件(图片、布局、字符串等),按类型和分辨率分类。 | 删除未引用资源,压缩图片格式(WebP/AVIF),矢量图替代位图。 |
assets/ | 原始资源文件(如配置文件、字体),需通过 AssetManager 访问。 | 按需动态加载非必要资源,压缩文本类资源(如 JSON)。 |
lib/ | Native 库(.so 文件),按 CPU 架构分类(armeabi-v7a, arm64-v8a 等)。 | 仅保留主流架构(如 arm64-v8a),或动态下载特定架构库。 |
META-INF/ | 包含应用签名信息(MANIFEST.MF , CERT.SF , CERT.RSA )。 | 无直接优化空间,但需确保签名有效性。 |
可以点击——Build——Analyze APK——看看apk那个部分比较大,可以优化一下。
四、瘦身优化
4.1 资源混淆、移除未使用资源
1. minifyEnabled
(代码压缩与混淆)
定义: 用于启用 代码压缩、混淆和优化,核心目标是减少代码体积并保护代码逻辑。
功能:
- 删除未使用的代码:移除未被引用的类、方法、字段(如废弃功能、调试代码)。
- 代码混淆:将类名、方法名、变量名替换为简短的无意义名称(如
a
、b
)。 - 代码优化:简化逻辑(如内联短方法、删除冗余代码)。
优化效果:
- DEX 体积减少:通常可减少 10%-30% 的代码体积。
- 安全性提升:混淆后的代码难以逆向分析。
2. shrinkResources
(资源压缩)
定义: 用于删除 未被代码引用的资源文件(如图片、布局、字符串),减少资源体积。
依赖条件: 必须与 minifyEnabled true
同时启用,因为它依赖代码分析结果判断资源是否被使用。
优化效果:
-
资源体积减少:移除未使用的图片、布局等,通常减少 5%-20% 的资源体积。
-
保留资源白名单:可通过
res/raw/keep.xml
指定强制保留的资源:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/force_keep_layout, @drawable/keep_image"
tools:discard="@layout/unsed2"/>
如果使用了discard属性,那么哪怕你使用到了资源,也会删除。
android {
buildTypes {
release {
minifyEnabled true // 必须同时启用
shrinkResources true // 删除未使用的资源
}
}
}
3. AndResGuard
(资源压缩)
AndResGuard 是腾讯开源的一款 Android 资源混淆工具,通过缩短资源文件(图片、布局、字符串等)的路径和名称,优化资源索引表(resources.arsc
)的结构,从而减少 APK 体积并增强安全性。
-
资源路径混淆:将冗长的资源路径(如
res/drawable-xxhdpi/icon_home.png
)替换为短路径(如r/d/a.png
)。 -
资源名称混淆:将资源名称替换为无意义的短字符串。
-
索引表优化:压缩
resources.arsc
的体积(减少字符串存储空间)。
如何使用 AndResGuard?
步骤 1:集成插件
在项目根目录的 build.gradle
中添加依赖:
buildscript {
dependencies {
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.21'
}
}
步骤 2:配置混淆规则
在 app/build.gradle
中配置 AndResGuard:
apply plugin: 'AndResGuard'
andResGuard {
enable = true // 启用资源混淆
// 白名单(保留不被混淆的资源)
whiteList = [
"R.drawable.icon_launcher", // 启动图标(避免动态加载失败)
"R.string.app_name", // 应用名称(某些系统功能依赖)
"R.xml.firebase_config" // Firebase 配置文件
]
// 压缩图片(可选)
compressFilePattern = ["*.png", "*.jpg", "*.webp"]
// 输出目录
outputDir = "apk_resguard"
}
步骤 3:构建混淆后的 APK
运行以下命令生成混淆包:
./gradlew resguardRelease
输出路径:app/apk_resguard/Release/app-release-resguard.apk
步骤 4:验证结果
- 体积对比:比较混淆前后 APK 的
resources.arsc
和资源目录体积。 - 反编译检查:使用 Android Studio 的 Analyze APK 或
apktool
解压 APK,确认资源路径已缩短。
shrinkResources true
和AndResGuard
的区别是:仅删除未使用的资源,不混淆路径。但是你会发现,为什么有些xml文件,明明开启了缩减,还是存在呢,因为他不是剔除,而是优化变小,没有内容了,几十B。
4.2 移除未使用的备用资源
一般开发我们都会引入各种依赖,这些依赖可能包含各种备用资源,如中文、英文、日韩文等等。如果我们不需要这些语言可以让他们不打包进入Apk
可以如下配置,减少这些语言
4.3 so库优化
SO(Shared Object)是 Android 平台上的动态链接库,用于存放 C/C++ 编写的原生代码(Native Code),位于项目的 jniLibs/
目录或第三方库的 lib/
目录下。每个 CPU 架构对应一个 SO 文件目录(如 arm64-v8a
、armeabi-v7a
)。
arm64-v8a | 64 位 ARM 架构(主流设备) |
---|---|
armeabi-v7a | 32 位 ARM 架构(旧设备) |
x86 | 32 位 Intel 架构(模拟器或旧设备) |
x86_64 | 64 位 Intel 架构(模拟器) |
移除不必要的架构
在 app/build.gradle
中配置 ndk.abiFilters
,仅保留目标架构:
android {
defaultConfig {
ndk {
abiFilters "arm64-v8a" // 只保留 64 位 ARM 架构
}
}
}
优化效果:若一个 SO 文件原为 5 MB,支持 4 种架构时总大小为 20 MB,保留 1 种后仅 5 MB。