Android 使用 Proguard 时 Volley 总是失败
Android Volley always fails with Proguard
目标是部署应用 obfuscation
和 minification
的应用程序。没有 minification
的常规构建工作正常。但是当 minifyEnabled
切换为 true 时,所有内容也会编译,但是所有 Volley
请求都会失败并返回错误回调 (onErrorResponse
),无论结果是否成功。
build.gradle
中的缩小配置:
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
}
}
proguard-rules.pro:
##---------------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
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
##---------------End: proguard configuration for Gson ----------
##---------------Begin: proguard configuration for Spongy Castle ----------
-keep class org.spongycastle.crypto.* {*;}
-keep class org.spongycastle.crypto.digests.* {*;}
-keep class org.spongycastle.crypto.encodings.* {*;}
-keep class org.spongycastle.crypto.engines.* {*;}
-keep class org.spongycastle.crypto.macs.* {*;}
-keep class org.spongycastle.crypto.modes.* {*;}
-keep class org.spongycastle.crypto.paddings.* {*;}
-keep class org.spongycastle.crypto.params.* {*;}
-keep class org.spongycastle.crypto.prng.* {*;}
-keep class org.spongycastle.crypto.signers.* {*;}
-keep class org.spongycastle.jcajce.provider.digest.** {*;}
-keep class org.spongycastle.jcajce.provider.keystore.** {*;}
-keep class org.spongycastle.jcajce.provider.symmetric.** {*;}
-keep class org.spongycastle.jcajce.spec.* {*;}
-keep class org.spongycastle.jce.** {*;}
-dontwarn javax.naming.**
##---------------End: proguard configuration for Spongy Castle ----------
# Configuration for Guava 18.0
#
# disagrees with instructions provided by Guava project: https://code.google.com/p/guava-libraries/wiki/UsingProGuardWithGuava
-keep class com.google.common.io.Resources {
public static <methods>;
}
-keep class com.google.common.collect.Lists {
public static ** reverse(**);
}
-keep class com.google.common.base.Charsets {
public static <fields>;
}
-keep class com.google.common.base.Joiner {
public static com.google.common.base.Joiner on(java.lang.String);
public ** join(...);
}
-keep class com.google.common.collect.MapMakerInternalMap$ReferenceEntry
-keep class com.google.common.cache.LocalCache$ReferenceEntry
#
-dontwarn javax.annotation.**
-dontwarn javax.inject.**
-dontwarn sun.misc.Unsafe
# Guava 19.0
-dontwarn java.lang.ClassValue
-dontwarn com.google.j2objc.annotations.Weak
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
# Security classes for keystore support
-dontwarn java.awt.**, javax.security.**, java.beans.**
# Volley
-dontwarn com.android.volley.**
-dontwarn com.android.volley.error.**
-keep class com.android.volley.** { *; }
-keep class com.android.volley.toolbox.** { *; }
-keep class com.android.volley.Response$* { *; }
-keep class com.android.volley.Request$* { *; }
-keep class com.android.volley.RequestQueue$* { *; }
-keep class com.android.volley.toolbox.HurlStack$* { *; }
-keep class com.android.volley.toolbox.ImageLoader$* { *; }
-keep interface com.android.volley.** { *; }
-keep class org.apache.commons.logging.*
所有使用的依赖项:
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.google.code.gson:gson:2.7'
compile 'com.android.volley:volley:1.0.0'
compile 'com.google.guava:guava:19.0'
compile 'org.apache.directory.studio:org.apache.commons.io:2.4'
compile 'com.madgag.spongycastle:core:1.54.0.0'
compile 'com.madgag.spongycastle:prov:1.54.0.0'
compile 'com.madgag.spongycastle:pkix:1.54.0.0'
compile 'com.madgag.spongycastle:pg:1.54.0.0'
除了 Volley 失败之外,Guava
中的 EventBus
也无法正常工作(订阅事件未获取)。我们有解决这些问题的方法吗?我应该在此处添加任何其他信息吗?
很难用日志查明任何错误,但是您应该在不使用混淆器的情况下尝试它。跳过 proguard 文件语法,看看它是否工作正常。
请确保您已启用 multidex,否则您的项目将无法执行。
android {
compileSdkVersion 21
buildToolsVersion "21.1.0"
defaultConfig {
...
minSdkVersion 14
targetSdkVersion 21
...
// Enabling multidex support.
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}
更多详情:https://developer.android.com/studio/build/multidex.html
应该承认,即使提供了所有信息,我的问题也很难分析,因为描述的错误有很多可能的来源。
我将从问题的结尾开始。 Guava 无法正常工作,因为 ProGuard 只是从我要打包的代码中排除了 Guava 的订阅方法。 ProGuard 删除了未使用的代码,只要 Subscribe-methods 被分析为未使用(甚至 IDE 不要将它们突出显示为已使用的代码),ProGuard 已决定删除这些方法。为了解决这个问题,我们应该从 ProGuard 的处理中保留 Subscribe-methods:
# Keep subscribe-methods from deletion
-keepclassmembers class ** {
@com.google.common.eventbus.Subscribe <methods>;
}
我的第一个问题 - 当 Volley 总是在所有被触发的请求中调用 onErrorResponse
回调。我为 Json-repsonses 使用了自定义反序列化器,它还检查服务器是否提供了一些必填字段(标有相应的注释)。当然,ProGuard 默认情况下无法与这些注释和反序列化器一起正常工作——这就是为什么我也必须保留这些实体的原因:
# To make right deserialization
-keepclassmembers class ** {
@com.some.package.server.JsonDeserializerWithOptions$FieldRequired public *;
}
-keep @interface com.some.package.server.JsonDeserializerWithOptions$FieldRequired
-keep class com.some.package.server.JsonDeserializerWithOptions
目标是部署应用 obfuscation
和 minification
的应用程序。没有 minification
的常规构建工作正常。但是当 minifyEnabled
切换为 true 时,所有内容也会编译,但是所有 Volley
请求都会失败并返回错误回调 (onErrorResponse
),无论结果是否成功。
build.gradle
中的缩小配置:
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
}
}
proguard-rules.pro:
##---------------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
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
##---------------End: proguard configuration for Gson ----------
##---------------Begin: proguard configuration for Spongy Castle ----------
-keep class org.spongycastle.crypto.* {*;}
-keep class org.spongycastle.crypto.digests.* {*;}
-keep class org.spongycastle.crypto.encodings.* {*;}
-keep class org.spongycastle.crypto.engines.* {*;}
-keep class org.spongycastle.crypto.macs.* {*;}
-keep class org.spongycastle.crypto.modes.* {*;}
-keep class org.spongycastle.crypto.paddings.* {*;}
-keep class org.spongycastle.crypto.params.* {*;}
-keep class org.spongycastle.crypto.prng.* {*;}
-keep class org.spongycastle.crypto.signers.* {*;}
-keep class org.spongycastle.jcajce.provider.digest.** {*;}
-keep class org.spongycastle.jcajce.provider.keystore.** {*;}
-keep class org.spongycastle.jcajce.provider.symmetric.** {*;}
-keep class org.spongycastle.jcajce.spec.* {*;}
-keep class org.spongycastle.jce.** {*;}
-dontwarn javax.naming.**
##---------------End: proguard configuration for Spongy Castle ----------
# Configuration for Guava 18.0
#
# disagrees with instructions provided by Guava project: https://code.google.com/p/guava-libraries/wiki/UsingProGuardWithGuava
-keep class com.google.common.io.Resources {
public static <methods>;
}
-keep class com.google.common.collect.Lists {
public static ** reverse(**);
}
-keep class com.google.common.base.Charsets {
public static <fields>;
}
-keep class com.google.common.base.Joiner {
public static com.google.common.base.Joiner on(java.lang.String);
public ** join(...);
}
-keep class com.google.common.collect.MapMakerInternalMap$ReferenceEntry
-keep class com.google.common.cache.LocalCache$ReferenceEntry
#
-dontwarn javax.annotation.**
-dontwarn javax.inject.**
-dontwarn sun.misc.Unsafe
# Guava 19.0
-dontwarn java.lang.ClassValue
-dontwarn com.google.j2objc.annotations.Weak
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
# Security classes for keystore support
-dontwarn java.awt.**, javax.security.**, java.beans.**
# Volley
-dontwarn com.android.volley.**
-dontwarn com.android.volley.error.**
-keep class com.android.volley.** { *; }
-keep class com.android.volley.toolbox.** { *; }
-keep class com.android.volley.Response$* { *; }
-keep class com.android.volley.Request$* { *; }
-keep class com.android.volley.RequestQueue$* { *; }
-keep class com.android.volley.toolbox.HurlStack$* { *; }
-keep class com.android.volley.toolbox.ImageLoader$* { *; }
-keep interface com.android.volley.** { *; }
-keep class org.apache.commons.logging.*
所有使用的依赖项:
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.google.code.gson:gson:2.7'
compile 'com.android.volley:volley:1.0.0'
compile 'com.google.guava:guava:19.0'
compile 'org.apache.directory.studio:org.apache.commons.io:2.4'
compile 'com.madgag.spongycastle:core:1.54.0.0'
compile 'com.madgag.spongycastle:prov:1.54.0.0'
compile 'com.madgag.spongycastle:pkix:1.54.0.0'
compile 'com.madgag.spongycastle:pg:1.54.0.0'
除了 Volley 失败之外,Guava
中的 EventBus
也无法正常工作(订阅事件未获取)。我们有解决这些问题的方法吗?我应该在此处添加任何其他信息吗?
很难用日志查明任何错误,但是您应该在不使用混淆器的情况下尝试它。跳过 proguard 文件语法,看看它是否工作正常。 请确保您已启用 multidex,否则您的项目将无法执行。
android {
compileSdkVersion 21
buildToolsVersion "21.1.0"
defaultConfig {
...
minSdkVersion 14
targetSdkVersion 21
...
// Enabling multidex support.
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}
更多详情:https://developer.android.com/studio/build/multidex.html
应该承认,即使提供了所有信息,我的问题也很难分析,因为描述的错误有很多可能的来源。
我将从问题的结尾开始。 Guava 无法正常工作,因为 ProGuard 只是从我要打包的代码中排除了 Guava 的订阅方法。 ProGuard 删除了未使用的代码,只要 Subscribe-methods 被分析为未使用(甚至 IDE 不要将它们突出显示为已使用的代码),ProGuard 已决定删除这些方法。为了解决这个问题,我们应该从 ProGuard 的处理中保留 Subscribe-methods:
# Keep subscribe-methods from deletion
-keepclassmembers class ** {
@com.google.common.eventbus.Subscribe <methods>;
}
我的第一个问题 - 当 Volley 总是在所有被触发的请求中调用 onErrorResponse
回调。我为 Json-repsonses 使用了自定义反序列化器,它还检查服务器是否提供了一些必填字段(标有相应的注释)。当然,ProGuard 默认情况下无法与这些注释和反序列化器一起正常工作——这就是为什么我也必须保留这些实体的原因:
# To make right deserialization
-keepclassmembers class ** {
@com.some.package.server.JsonDeserializerWithOptions$FieldRequired public *;
}
-keep @interface com.some.package.server.JsonDeserializerWithOptions$FieldRequired
-keep class com.some.package.server.JsonDeserializerWithOptions