首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >读者点单·09|Android 包体积治理:从 R8 到资源混淆的工程化全链路

读者点单·09|Android 包体积治理:从 R8 到资源混淆的工程化全链路

作者头像
陆业聪
发布2026-07-03 20:21:30
发布2026-07-03 20:21:30
00
举报

📚 读者点单·端午投票系列 · 第9/10篇

✅ 第1篇:Android 性能治理的「全景图」

✅ 第2篇:Android 启动优化实战

✅ 第3篇:Compose 与传统 View 混用的 12 个真实坑

✅ 第4篇:Android 内存治理实战

✅ 第5篇:Token 节省专题

✅ 第6篇:App 掉帧全链路拆解

✅ 第7篇:ANR 治理实战

✅ 第8篇:AI × Android 端侧落地

👉 第9篇:Android 包体积治理(本篇)

⏳ 第10篇:系列复盘·完整工程蓝图

📰 科技要闻

• AGP 8.12.0 正式引入 optimized resource shrinking,R8 与资源压缩深度整合,一条 Gradle 配置同时优化代码和资源体积(Android Developers,6.18)

• 央行官宣 6 月 29-30 日新增隔夜逆回购操作,不限量满足银行短期资金需求,对冲季末 2.8 万亿资金缺口(新浪财经,6.29)

• A 股半年报预告拉开序幕,已有 19 家公司发布业绩预告,长川科技等半导体企业表现亮眼(证券日报,6.28)

• XREAL 正式发布 AURA 空间计算眼镜,基于 Android XR 平台+Gemini AI,售价预计 2026 年底开售(XREAL 官方,6.16)

上周有个读者私信我:「我们 App 的 APK 已经 120MB 了,领导让我砍到 60MB 以内,给我两周时间,我根本不知道从哪下手。」

说实话,这个问题我太熟了。三年前我自己也经历过一模一样的场景——接到一个「包体积瘦身 50%」的 OKR,打开 APK Analyzer 一看,满屏红色的 so 库和图片资源,感觉无从下手。但两周后我不仅达标了,还把整套方法论沉淀成了团队的包体积 CI 红线。

今天这篇就是把我踩过的坑、验证过的方案、以及 2026 年 AGP 8.12 带来的新武器,全部整理成一条从「诊断→治理→防劣化」的工程化全链路。不管你是刚接到瘦身任务的新手,还是想建立长期防线的架构师,这篇都能给你一张清晰的路线图。

1. 第一步永远是「解剖」:APK 到底胖在哪?

瘦身之前先称体重。打开 Android Studio 的 APK Analyzer(Build → Analyze APK),你会看到这样一张饼图:

目录

内容

典型占比

classes*.dex

Java/Kotlin 字节码

15%~25%

lib/

Native so 库

30%~50%

res/

图片/布局/动画

20%~35%

assets/

字体/模型/配置

5%~15%

resources.arsc

资源索引表

3%~8%

我的经验是:大多数团队一上来就想压图片,但其实 lib/ 才是最大的胖子。尤其是集成了 Flutter、音视频 SDK、AI 推理引擎的大型 App,lib/ 轻松占到全包 50% 以上。所以我的治理优先级排序是:

APK Analyzer 定位胖子

lib/ 占比 > 30%?

✅ 是 → 优先治理 so 库(ABI 裁剪 + 动态下发)

❌ 否 → 优先治理 res/ + dex(R8 + 图片压缩)

这里还有个小技巧:用命令行拆包可以更精确地看到每个 so 的大小:

代码语言:javascript
复制
# 解压 APK 并按大小排序
unzip -l app-release.apk \
| grep "lib/" \
| sort -rn -k1 \
| head -20

2. R8 Full Mode:每个团队都应该开的「白崩」优化

R8 是 Google 在 2019 年替代 ProGuard 的官方代码缩减/混淆工具。但说实话,到 2026 年了,我见过的大多数团队还停留在「开了 minifyEnabled 就等于做过优化」的阶段。实际上,R8 Full Mode + AGP 8.12 的整合优化能再多厊 20%~50%

2.1 开启 R8 Full Mode

AGP 8.0+ 默认开启了 R8 Full Mode,但很多老项目升级后因为兼容问题又关掉了。这里要确认两个关键配置:

代码语言:javascript
复制
// gradle.properties
android.enableR8.fullMode=
true// build.gradle.kts
android {
buildTypes {
release {
isMinifyEnabled =
true
isShrinkResources =
true
proguardFiles(
getDefaultProguardFile(
"proguard-android
                -optimize.txt"
),
"proguard-rules
              .pro"
)
}
}
}

2.2 R8 的三把刀:缩减、优化、混淆

R8 做的事情分三层:

能力

作用

收益

Tree Shaking

删除未使用类/方法

dex 减 15%~40%

Optimization

内联/常量折叠/死代码消除

dex 再减 5%~15%

Obfuscation

类名/方法名缩短为 a/b/c

dex 减 3%~8%

Full Mode 相比默认模式的核心区别:它会更激进地移除“看起来被引用但实际不可达”的代码。典型场景是第三方库的内部类——比如你只用了 OkHttp 的 GET 请求,Full Mode 能把 WebSocket、HTTP/2 Push 等你永远不会触发的代码全部删掉。

2.3 AGP 8.12 新武器:Optimized Resource Shrinking

2026 年 6 月刚发布的 AGP 8.12.0 带来了一个重磅特性:优化的资源缩减。这不是简单的 shrinkResources = true,而是 R8 与资源缩减引擎的深度联动:

之前的流程是:R8 先删代码 → 资源缩减器再删资源,两步独立。现在 AGP 8.12 将两者整合成一个 pass,R8 能感知到「这个资源 ID 虽然在代码里被引用,但引用它的代码已经被我删了」,从而实现更彻底的死资源清理。

代码语言:javascript
复制
// AGP 8.12+ 启用整合优化
android {
buildTypes {
release {
isMinifyEnabled =
true
isShrinkResources =
true
// 整合优化自动生效
// 无需额外配置
}
}
optimization {
// 可选:查看深度报告
keepRules {
ignoreExternalDeps =
true
}
}
}

实测数据:我在一个中型项目(72 个模块)上测试,AGP 8.12 的整合优化比单独开 shrinkResources 又多减了 4.2MB,主要来自“废弃功能但资源未删”的历史债务。

3. 资源混淆:AndResGuard / AabResGuard / shrinkResources

R8 解决的是代码层的胖,但资源层还有一个被很多人忽略的浪费点:resources.arsc 里存放的资源路径字符串本身就很占体积

举个例子,res/drawable-xxhdpi-v4/ic_user_profile_avatar_placeholder.png 这样的路径有 60+ 字符,而你的 App 可能有上千个这样的资源。资源混淆工具把这些路径全部缩短为 r/a/b.png,效果立竿见影。

工具

出品

适用场景

收益

AndResGuard

微信团队

APK 发布

1~3MB

AabResGuard

字节跳动

AAB 发布

1~2MB

AGP shrinkRes

Google 官方

APK/AAB 通用

0.5~2MB

我的建议是:如果你还在用 APK 发布(国内市场大多数情况),AndResGuard 仍然是最稳定的选择。它除了路径混淆,还会用 7zip 重新压缩 APK,这一步额外又能省 0.5~1MB。

代码语言:javascript
复制
// build.gradle.kts
// AndResGuard 配置示例
andResGuard {
mappingFile = null
use7zip = true
useSign = true
keepRoot = false
// 白名单:不能混淆的资源
whiteList = listOf(
"R.mipmap.ic_launcher",
"R.drawable.notification*"
)
compressFilePattern =
listOf(
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
"resources.arsc"
)
}

踩坑提醒:Notification 的图标资源一定要加白名单!Android 系统会通过原始资源名查找图标,混淆后会变成白块。另外 AppWidget、动态 Feature 的入口 Activity 也要注意。

4. 图片资源治理:从「无脑删图」到工程化流水线

很多团队治理图片的方式是「开个会让设计师压图」,效果一般且不可持续。我推荐的工程化思路是分四层:

4.1 格式升级:PNG → WebP

WebP 有损压缩比 PNG 小 25%~35%,无损 WebP 比 PNG 小 10%~25%。AGP 自带了构建时自动转换:

代码语言:javascript
复制
// AGP 自动转 WebP
// minSdk >= 18 时自动启用
android {
buildFeatures {
// 确保未禁用资源处理
androidResources =
true
}
}// 批量手动转换(CI 脚本)
find app/src/main/res \
-name "*.png" \
-not -name "*.9.png" \
-exec cwebp -q 80 \
{} -o {}.webp \;

4.2 矢量替代:SVG → VectorDrawable

24dp 以下的图标,一个 VectorDrawable XML 只有 200~500 字节,而对应的 PNG 可能有 3~10KB(还要乘以多个 DPI 变体)。我的规则是:凡是纯色图标,一律用 Vector

4.3 网络图替代本地图

这个策略特别适合运营位图片。比如开屏广告、Banner、活动页背景——这些图片变化频繁,完全不应该打进 APK。放 CDN,通过接口下发 URL,既能瘦包又能灵活更新。

4.4 CI 红线防劣化

单次治理只是开始,不设红线就会反弹。我的做法是在 CI 加一步检查:

代码语言:javascript
复制
# CI 图片体积红线检查
MAX_SINGLE_IMAGE=100  # KB
MAX_TOTAL_RES=15    # MBfind app/src/main/res \
-name "*.png" \
-size +${MAX_SINGLE_IMAGE}k \
-exec echo \
"❌ 超大图片: {}" \;TOTAL=$(du -sm \
app/src/main/res \
| awk '{print $1}')if [ $TOTAL -gt \
$MAX_TOTAL_RES ]; then
echo "❌ res/ 超限"
exit 1
fi

5. so 库瘦身:APK 里最胖的一块肉

说实话,对于集成了音视频 SDK、地图 SDK、AI 推理库的 App,lib/ 经常占到全包 50% 以上。这块的治理路径有三条:

5.1 ABI 裁剪:立竿见影的 50% 瘦身

国内 2026 年的现实是:99%+ 的设备支持 arm64-v8a。如果你还在打 armeabi-v7a,建议今天就砷掉:

代码语言:javascript
复制
// build.gradle.kts
android {
defaultConfig {
ndk {
// 只保留 arm64
abiFilters +=
"arm64-v8a"
}
}
}

就这一行配置,如果你之前同时打了 armeabi-v7a 和 arm64-v8a,瞬间厊掉 lib/ 一半体积。我见过最夸张的 case 是一个 App 同时打了四种 ABI,只保留 arm64 就减了 75%。

5.2 动态下发:把大 so 从 APK 里拉出来

对于体积特别大但只在特定场景使用的 so(比如视频编辑引擎、AI 模型推理库),可以在用户首次进入该功能时再从 CDN 下载:

代码语言:javascript
复制
class SoLoader(
private val ctx:
Context
) {
suspend fun loadIfNeeded(
soName: String
) {
val localFile =
File(
ctx.filesDir,
"so/$soName"
)
if (!localFile.exists()) {
// 从 CDN 下载
downloadFrom(
"$CDN_BASE/$soName",
localFile
)
}
System.load(
localFile
.absolutePath
)
}
}

注意:动态下发 so 需要做好完整性校验(MD5/SHA256)和版本管理。另外,安全合规要求下载的 so 不能放在可被外部访问的目录。

5.3 编译优化:给 so 瘦身的细节手段

如果你能控制 Native 代码的编译(自研 so 或可重编译的三方库),还有这些手段:

开启 LTO(Link Time Optimization):跨编译单元优化,典型可减 10%~20%

-fvisibility=hidden:隐藏非导出符号,减少动态符号表体积

strip 调试信息:Release 包必须 strip,多数 AGP 默认已做

-Oz 优化级别:比 -Os 更激进的体积优化,牺牲少量性能

6. AAB + Dynamic Feature:按需下发的终极方案

Google 官方数据:AAB 格式平均减少 47% 安装包体积。这个数字我在实测中也基本验证了,在一个打包了 4 种 ABI + 3 种密度资源的 App 上,从 APK 切换到 AAB 后用户实际下载体积减少了 52%。

AAB 的核心原理很简单:它不是一个完整的安装包,而是一个「生成器」。Google Play 根据用户设备的屏幕密度、CPU 架构、语言,动态生成一个尺寸最小的专属 APK。

6.1 国内怎么用 AAB?

「我们不上 Google Play」——这是我听到最多的反驳。但其实国内也能用 AAB 的思路:

华为应用市场:2025 年起支持 AAB 格式上架

自建分发服务:用 bundletool 从 AAB 生成多个按设备特征拆分的 APK

企业内发:内部应用可以按设备型号分发不同 APK

代码语言:javascript
复制
# bundletool 生成设备专属 APK
bundletool build-apks \
--bundle=app.aab \
--output=app.apks \
--connected-device# 查看按设备拆分后的大小
bundletool get-size total \
--apks=app.apks

6.2 Dynamic Feature:按需加载功能模块

Dynamic Feature Module 把低频功能(扫码、视频编辑、AR 特效)拆成独立模块,用户打开时才下载。实测效果:

模块

体积

使用率

拆出后主包减少

视频编辑

18MB

12%

18MB

AR 模块

12MB

5%

12MB

扫码引擎

4MB

35%

4MB

7. 总结:我的包体积治理优先级排序

如果你只有两周时间,我建议的执行顺序是:

第 1 天:APK Analyzer 定位各目录占比,确定主攻方向

第 2-3 天:ABI 裁剪(立竿减 30%~50%)

第 4-5 天:R8 Full Mode + AGP 8.12 整合优化(再减 15%~30%)

第 6-8 天:图片 WebP 转换 + 运营图上 CDN(再减 10%~20%)

第 9-10 天:AndResGuard 资源混淆(再减 1~3MB)

第 11-14 天:建立 CI 红线 + 自动化监控(防反弹)

包体积治理不是一锤子买卖。真正难的不是「瘦下来」,而是「不反弹」。我见过太多团队花两周从 100MB 厊到 60MB,然后三个月后又回到 90MB——因为新需求不断引入新的 SDK、新的大图片、新的 so 库。

所以治理的终点不是一个数字,而是一套机制。CI 红线、模块化拆分、定期审计——把这些变成团队的日常工作流,才能真正守住胜利果实。

明天就是系列的最后一篇——系列复盘:把 9 篇拼成一张完整的 Android 性能治理工程蓝图。我会把所有篇章的核心方法论串起来,帮你建立一个“从哪入手、按什么顺序、用什么工具”的完整决策树。别忘了关注,明天见。

📚 读者点单·端午投票系列 · 第9/10篇

基于端午《聊聊学习节奏》评论区读者票选生成的系列文章

✅ 第1篇:Android 性能治理的「全景图」

✅ 第2篇:Android 启动优化实战

✅ 第3篇:Compose 与传统 View 混用的 12 个真实坑

✅ 第4篇:Android 内存治理实战

✅ 第5篇:Token 节省专题

✅ 第6篇:App 掉帧全链路拆解

✅ 第7篇:ANR 治理实战

✅ 第8篇:AI × Android 端侧落地

👉 第9篇:Android 包体积治理(本篇)

⏳ 第10篇:系列复盘·完整工程蓝图

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陆业聪 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档