启用 ProGuard 时 Retrofit 2 不发送数据
Retrofit 2 not sending data when ProGuard is enabled
我尝试使用 Retrofit 2 登录我的用户。(基本上是使用基本 header 登录 URL 的 GET)它运行良好但是一旦我 ProGuard 它,Header 不再发送授权。 (查看日志输出)
示例代码:
用户模型:
public interface UserService {
@GET(GET_LOGIN)
Observable<User> login(@Header("Authorization") String basic);
}
登录Activity:
public void onClick(View v) {
mRetrofit.create(UserService.class)
.login(Credentials.basic(email, password))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(user -> {
UserHelper.save(LoginActivity.this, user);
}, throwable -> Dog.d);
}
Proguard 文件:
# Retrofit
-dontwarn retrofit2.**
-dontwarn org.codehaus.mojo.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepattributes *Annotation*
-keepclasseswithmembers class * {
@retrofit.* <methods>;
}
-keepclasseswithmembers interface * {
@retrofit.* <methods>;
}
日志(proguard):
D/OkHttp: --> GET http://passport-supercairos.rhcloud.com/users/login HTTP/1.1
D/OkHttp: User-Agent: VirtualPassport-Client {Android-23} {Aquaris_E5}
D/OkHttp: Cache-Control: max-stale=10800
D/OkHttp: --> END GET
D/OkHttp: <-- HTTP/1.1 401 Unauthorized (258ms)
D/OkHttp: Date: Fri, 19 Feb 2016 12:57:19 GMT
D/OkHttp: X-Powered-By: Express
D/OkHttp: WWW-Authenticate: Basic realm="Users"
D/OkHttp: Keep-Alive: timeout=15, max=100
D/OkHttp: Connection: Keep-Alive
D/OkHttp: Transfer-Encoding: chunked
D/OkHttp: Content-Type: text/plain
D/OkHttp: OkHttp-Sent-Millis: 1455886639681
D/OkHttp: OkHttp-Received-Millis: 1455886639787
D/OkHttp: Unauthorized
D/OkHttp: <-- END HTTP (12-byte body)
日志(non-proguard):
D/OkHttp: --> GET http://passport-supercairos.rhcloud.com/users/login HTTP/1.1
D/OkHttp: User-Agent: VirtualPassport-Client {Android-23} {Aquaris_E5}
D/OkHttp: Cache-Control: max-stale=10800
D/OkHttp: Authorization: Basic ZG9yb2ZyanVAZ21haWwuY29tOmN2dnZ2dnY=
D/OkHttp: --> END GET
D/OkHttp: <-- HTTP/1.1 401 Unauthorized (258ms)
D/OkHttp: Date: Fri, 19 Feb 2016 12:57:19 GMT
D/OkHttp: X-Powered-By: Express
D/OkHttp: WWW-Authenticate: Basic realm="Users"
D/OkHttp: Keep-Alive: timeout=15, max=100
D/OkHttp: Connection: Keep-Alive
D/OkHttp: Transfer-Encoding: chunked
D/OkHttp: Content-Type: text/plain
D/OkHttp: OkHttp-Sent-Millis: 1455886639681
D/OkHttp: OkHttp-Received-Millis: 1455886639787
D/OkHttp: Unauthorized
D/OkHttp: <-- END HTTP (12-byte body)
我终于成功了。这是关于 Retrofit 2
的 proguard 配置
# Retrofit
-dontwarn retrofit2.**
-dontwarn org.codehaus.mojo.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepattributes *Annotation*
-keepattributes RuntimeVisibleAnnotations
-keepattributes RuntimeInvisibleAnnotations
-keepattributes RuntimeVisibleParameterAnnotations
-keepattributes RuntimeInvisibleParameterAnnotations
-keepattributes EnclosingMethod
-keepclasseswithmembers class * {
@retrofit2.* <methods>;
}
-keepclasseswithmembers interface * {
@retrofit2.* <methods>;
}
谢谢@xudshen
更新
主要问题:我使用了proguard-android-optimize 所以我应该添加:
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
我还切换回了 square 提供的常规 Retrofit 2 proguard 配置:
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on RoboVM on iOS. Will not be used at runtime.
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
添加到@Romain 的回答
您需要添加到 proguard 文件
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
如果您正在使用@Header、@Query...
参考来自这里
添加 Retrofit 2 与 Proguard 代码混淆器的兼容性
-dontwarn retrofit.**
-keep class retrofit.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-dontwarn java.lang.invoke.*
-keep class com.elephantmobile.ui.remote.model.** { *; }
-dontwarn retrofit.appengine.UrlFetchClient
-keepclasseswithmembers class * {
@retrofit.http.* <methods>;
}
-keepclassmembernames interface * {
@retrofit.http.* <methods>;
}
-dontwarn retrofit2.Platform$Java8
另一个简单的解决方案
使用来自支持注解的@keep
https://developer.android.com/reference/android/support/annotation/Keep.html
@Keep
interface APIService
{
@GET("/user/auth")
fun auth(@Header(Constants.AUTHORIZATION) authorization: String): Call<User>
}
对我来说,使用注解@SerializedName
public class YourJsonClass{
@SerializedName("name") String username;
...
}
终于找到了。
如果你使用 Gson
就试试这个,
将此添加到改装 pro-guard 中:
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
然后在您的模型中使用 @SerializedName("name")
。kotlin
示例:
class PaymentRequestModel (
@SerializedName("name")
@Expose
var name : String = "",
}
您需要添加
@SerializedName("yourInputParameter")
在您的 bean(模型)中 class 用于您的请求正文
例如
public class YourClass{
@SerializedName("yourInputParameter") String yourInputParameter;
...
}
它会起作用
因为现在 retrofit 无法读取您的请求正文,因为 proguard(minifyEnabled) 为真
在您的请求正文中添加 @SerializedName 之后,它肯定对您有用
将此添加到 progaurd
-keep public class com.data.YOurDataModels.* {
public void set*(***);
public *** get*();
public protected private *;
}
只需在您的数据上添加 @Keep class
@Keep
data class ClassPojo(
@SerializedName("MESSAGE") val message: String,
@SerializedName("STATUS") val status: String)
我尝试使用 Retrofit 2 登录我的用户。(基本上是使用基本 header 登录 URL 的 GET)它运行良好但是一旦我 ProGuard 它,Header 不再发送授权。 (查看日志输出)
示例代码:
用户模型:
public interface UserService {
@GET(GET_LOGIN)
Observable<User> login(@Header("Authorization") String basic);
}
登录Activity:
public void onClick(View v) {
mRetrofit.create(UserService.class)
.login(Credentials.basic(email, password))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(user -> {
UserHelper.save(LoginActivity.this, user);
}, throwable -> Dog.d);
}
Proguard 文件:
# Retrofit
-dontwarn retrofit2.**
-dontwarn org.codehaus.mojo.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepattributes *Annotation*
-keepclasseswithmembers class * {
@retrofit.* <methods>;
}
-keepclasseswithmembers interface * {
@retrofit.* <methods>;
}
日志(proguard):
D/OkHttp: --> GET http://passport-supercairos.rhcloud.com/users/login HTTP/1.1
D/OkHttp: User-Agent: VirtualPassport-Client {Android-23} {Aquaris_E5}
D/OkHttp: Cache-Control: max-stale=10800
D/OkHttp: --> END GET
D/OkHttp: <-- HTTP/1.1 401 Unauthorized (258ms)
D/OkHttp: Date: Fri, 19 Feb 2016 12:57:19 GMT
D/OkHttp: X-Powered-By: Express
D/OkHttp: WWW-Authenticate: Basic realm="Users"
D/OkHttp: Keep-Alive: timeout=15, max=100
D/OkHttp: Connection: Keep-Alive
D/OkHttp: Transfer-Encoding: chunked
D/OkHttp: Content-Type: text/plain
D/OkHttp: OkHttp-Sent-Millis: 1455886639681
D/OkHttp: OkHttp-Received-Millis: 1455886639787
D/OkHttp: Unauthorized
D/OkHttp: <-- END HTTP (12-byte body)
日志(non-proguard):
D/OkHttp: --> GET http://passport-supercairos.rhcloud.com/users/login HTTP/1.1
D/OkHttp: User-Agent: VirtualPassport-Client {Android-23} {Aquaris_E5}
D/OkHttp: Cache-Control: max-stale=10800
D/OkHttp: Authorization: Basic ZG9yb2ZyanVAZ21haWwuY29tOmN2dnZ2dnY=
D/OkHttp: --> END GET
D/OkHttp: <-- HTTP/1.1 401 Unauthorized (258ms)
D/OkHttp: Date: Fri, 19 Feb 2016 12:57:19 GMT
D/OkHttp: X-Powered-By: Express
D/OkHttp: WWW-Authenticate: Basic realm="Users"
D/OkHttp: Keep-Alive: timeout=15, max=100
D/OkHttp: Connection: Keep-Alive
D/OkHttp: Transfer-Encoding: chunked
D/OkHttp: Content-Type: text/plain
D/OkHttp: OkHttp-Sent-Millis: 1455886639681
D/OkHttp: OkHttp-Received-Millis: 1455886639787
D/OkHttp: Unauthorized
D/OkHttp: <-- END HTTP (12-byte body)
我终于成功了。这是关于 Retrofit 2
的 proguard 配置# Retrofit
-dontwarn retrofit2.**
-dontwarn org.codehaus.mojo.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepattributes *Annotation*
-keepattributes RuntimeVisibleAnnotations
-keepattributes RuntimeInvisibleAnnotations
-keepattributes RuntimeVisibleParameterAnnotations
-keepattributes RuntimeInvisibleParameterAnnotations
-keepattributes EnclosingMethod
-keepclasseswithmembers class * {
@retrofit2.* <methods>;
}
-keepclasseswithmembers interface * {
@retrofit2.* <methods>;
}
谢谢@xudshen
更新
主要问题:我使用了proguard-android-optimize 所以我应该添加:
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
我还切换回了 square 提供的常规 Retrofit 2 proguard 配置:
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on RoboVM on iOS. Will not be used at runtime.
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
添加到@Romain 的回答 您需要添加到 proguard 文件
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
如果您正在使用@Header、@Query...
参考来自这里
添加 Retrofit 2 与 Proguard 代码混淆器的兼容性
-dontwarn retrofit.**
-keep class retrofit.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-dontwarn java.lang.invoke.*
-keep class com.elephantmobile.ui.remote.model.** { *; }
-dontwarn retrofit.appengine.UrlFetchClient
-keepclasseswithmembers class * {
@retrofit.http.* <methods>;
}
-keepclassmembernames interface * {
@retrofit.http.* <methods>;
}
-dontwarn retrofit2.Platform$Java8
另一个简单的解决方案 使用来自支持注解的@keep https://developer.android.com/reference/android/support/annotation/Keep.html
@Keep
interface APIService
{
@GET("/user/auth")
fun auth(@Header(Constants.AUTHORIZATION) authorization: String): Call<User>
}
对我来说,使用注解@SerializedName
public class YourJsonClass{
@SerializedName("name") String username;
...
}
终于找到了。
如果你使用 Gson
就试试这个,
将此添加到改装 pro-guard 中:
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
然后在您的模型中使用 @SerializedName("name")
。kotlin
示例:
class PaymentRequestModel (
@SerializedName("name")
@Expose
var name : String = "",
}
您需要添加
@SerializedName("yourInputParameter")
在您的 bean(模型)中 class 用于您的请求正文
例如
public class YourClass{
@SerializedName("yourInputParameter") String yourInputParameter;
...
}
它会起作用
因为现在 retrofit 无法读取您的请求正文,因为 proguard(minifyEnabled) 为真
在您的请求正文中添加 @SerializedName 之后,它肯定对您有用
将此添加到 progaurd
-keep public class com.data.YOurDataModels.* {
public void set*(***);
public *** get*();
public protected private *;
}
只需在您的数据上添加 @Keep class
@Keep
data class ClassPojo(
@SerializedName("MESSAGE") val message: String,
@SerializedName("STATUS") val status: String)