问题及分析
近期在项目打包时遇到一个奇怪的问题(冒烟没发现,测试发现的,非常尴尬):同一个业务组件在一个老项目中集成没问题,在新创建的项目中打release包就有问题,post请求(retrofit 2.7.1 )的body一直为null,debug包没问题。很明显这是个混淆造成的问题,但为什么同样的组件、同样的proguard-rules.pro打出来的包却一个没问题,一个有问题呢?
查询相关资料后,发现是代码压缩器不同的缘故。
新项目的gradle创建版本:
classpath 'com.android.tools.build:gradle:4.0.2'
老项目的gradle插件版本:
classpath 'com.android.tools.build:gradle:3.3.2'
在官方文档中明确说明了了gradle 插件3.4.0之后不再使用Proguard进行混淆,而是使用R8编译期,当然R8完全兼容原proguard-rules.pro中指定的规则使得插件可以平滑升级。
从资料中可以了解R8相比Proguard会“压缩得更狠”。在业务组件中我是通过@SerializedName
注解而非@Keep
注解处理bean类字段,由于Gson使用反射创建bean对象并对对象的字段进行填充,这在R8优化过程中是不可见的,相应的字段直接被抹掉。所以在不修改业务组件代码的前提下,只要能keep住@SerializedName
注解的字段即可。
解决办法
原Gson的混淆规则:
-keepattributes Annotation
-keep class sun.misc.Unsafe { *; }
-keep class com.idea.fifaalarmclock.entity.*
-keep class com.google.gson.stream.* { *; }
-keepattributes EnclosingMethod
-keep class com.google.gson.** {*;}
-keep class com.google.**{*;}
修改为:
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
##---------------End: proguard configuration for Gson ----------
利用consumerProguardFiles解放宿主工程
作为打包人员最怕就是引入一个新的业务组件时需要去询问对应开发相关混淆规则,甚至版本迭代有时需要进行规则更新。可以在组件打aar时使用consumerProguardFiles来顺带将混淆规则打进去,减少这种无谓的沟通成本。R8在打包过程中会将这些proguard.txt进行合并和应用。
android {
......
defaultConfig {
......
consumerProguardFiles "consumer-rules.pro"
}
}