如何先对Android库执行Proguard/R8再处理主应用,模拟外部依赖场景?
我正在开发一款闭源Android库,同时维护一个依赖该库的Android应用。目前库的release构建能生成符合预期的混淆.aar,且consumer-rules.pro配置正确,外部应用依赖该aar时功能正常。但当应用通过implementation project(':my-lib')本地依赖库时,Proguard/R8会将库和应用源码聚合后统一处理,导致库中部分该混淆的代码未混淆、该保留的被移除,自定义mapping也不生效。
我希望在本地依赖的情况下,实现和外部应用依赖aar完全一致的效果,不想频繁发布测试包来验证。
项目关键文件结构
my-project/ ├─ my-app/ │ ├─ ... │ ├─ build.gradle │ ├─ proguard-rules.pro ├─ my-lib/ │ ├─ ... │ ├─ build.gradle │ ├─ custom-mapping.txt │ ├─ consumer-rules.pro │ ├─ proguard-rules.pro
my-app的build.gradle
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } ... dependencies { ... implementation project(':my-lib') }
my-lib的build.gradle
android { defaultConfig { ... consumerProguardFiles "consumer-rules.pro" } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } }
my-lib的proguard-rules.pro
-applymapping "custom-mapping.txt" # Place every obfuscated class in a single package -flattenpackagehierarchy 'com.mycompany.mylib.obfuscated' # Do not attempt to shrink the code when building this library as a standalone, otherwise all of # the code will get stripped, ending up with an empty aar file -dontshrink # Here are my keep rules ...
my-lib的consumer-rules.pro
# Some keep rules related to Android internal classes that I rely on in my library # Field that shouldn't be stripped if the class is present -keepclassmembers class com.mycompany.mylib.obfuscated.z.z { # <-- the z.z comes from the custom mapping I'm applying to ensure it's always obfuscated the same way # Fields that I want to keep and that would be shrunk without specifying it ... }
解决方案
1. 直接依赖库的release预混淆产物
修改my-app的依赖配置,指定使用my-lib已经完成混淆的release变体,而非合并源码重新处理:
dependencies { ... implementation project(path: ':my-lib', configuration: 'release') }
这种方式和外部应用依赖aar的行为完全一致,Gradle会直接使用my-lib构建好的混淆aar,避免源码聚合后的统一混淆。
2. 配置构建类型的依赖对齐(可选)
如果需要在应用的debug构建中也使用库的release产物,或者统一构建类型的依赖规则,先在my-lib的build.gradle中开启全变体发布:
android { publishNonDefault true // 默认仅发布release变体,开启后会发布所有构建类型产物 }
然后在my-app中针对不同构建类型指定依赖:
dependencies { debugImplementation project(path: ':my-lib', configuration: 'release') releaseImplementation project(path: ':my-lib', configuration: 'release') }
3. 确保自定义mapping生效
当依赖预混淆的库时,my-lib的-applymapping规则已经在自身release构建阶段生效,应用的Proguard只会加载库的consumer-rules.pro规则,不会修改库已有的混淆结果,完美模拟外部依赖场景。
4. 修复依赖传递问题
依赖预混淆aar时如果出现依赖缺失,可将my-lib中的implementation依赖改为api,确保依赖能自动传递给my-app:
// 在my-lib的build.gradle中 dependencies { api 'com.some.dependency:xxx:1.0.0' }
内容的提问来源于stack exchange,提问作者Paul-Etienne

