如何实现APK中res目录扁平短文件名的资源混淆效果
APK res目录短文件名扁平化效果的实现说明
核心结论
这个效果不是Kotlin、ProGuard/R8或者普通Gradle本地编译流程实现的,也不是第三方AAB转APK工具默认生成的,是Google Play在处理开发者上传的Android App Bundle(AAB)、生成面向终端用户分发的拆分APK时,自动执行的服务端资源优化步骤,属于资源混淆的一种。
实现原理
- 本地通过Gradle构建的通用APK、开发者本地导出的AAB安装包,默认都会保留标准的res目录结构:按资源类型、屏幕密度、语言等维度划分
drawable-xx、layout、values-xx这类子文件夹,资源也保留语义化文件名。你之前配置的shrinkResources参数仅会删除未被引用的冗余资源,不会修改保留资源的存储路径和文件名。 - 当AAB上传到Google Play后,服务端构建流水线在生成适配不同设备配置的Split APK时,会重写包内的
resources.arsc资源映射表:将原有的长路径映射(例如res/drawable-xxhdpi/ic_launcher.png)替换为短路径映射(例如res/BZ.9.png),同时把所有资源文件移动到/res根目录下,重命名为[0-9A-Z]组合的双字符递增短文件名,9patch类资源会保留.9.png后缀。 - 反编译/APK编辑工具之所以能展示出正常的res子文件夹结构,是因为工具解析
resources.arsc时,会根据资源ID携带的类型、适配配置信息还原出逻辑上的分类结构,并不是真的从APK压缩包内读取到了对应的子目录。 - 开源AAB转APK工具bundletool在本地执行拆分打包时,默认不会开启这个资源混淆步骤,只有Google Play服务端的分发构建流程会默认追加这个优化。
为什么你配置的R8/ProGuard没有生效
ProGuard和接替它的R8,作用范围仅局限于DEX文件内的字节码:只会混淆类名、方法名、字段名,删除无用代码,完全不会修改资源文件、也不会改动resources.arsc里的资源路径映射,自然不可能实现res目录扁平化的效果。
你之前使用的Gradle配置:
buildTypes { release { useProguard false shrinkResources true minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } debug { minifyEnabled = true } }
所有配置项都只作用于代码压缩和冗余资源清理,没有涉及资源名混淆的相关配置,本地构建出来的APK自然会保留标准的res目录结构。
本地构建实现该效果的方法
如果想在本地打出的APK里实现同样的res目录短名扁平化效果,不需要依赖Google Play的服务端处理,可以直接接入专门的Android资源混淆工具,目前最常用的是微信开源的AndResGuard:它可以作为Gradle构建任务的一环插入打包流程,实现和Google Play完全一致的资源混淆效果,同步修改resources.arsc映射、重命名资源文件、扁平化res目录,同时还能进一步缩减APK体积。
目前Android Gradle Plugin内置的资源优化能力暂未开放资源名混淆的可配置参数,无法仅通过修改内置build.gradle配置实现该效果。
内容的提问来源于stack exchange,提问作者Hamid Habibi
相关产品推荐
相关产品推荐

