启用 ProGuard 时改造 2 不发送数据

Posted

技术标签:

【中文标题】启用 ProGuard 时改造 2 不发送数据【英文标题】:Retrofit 2 not sending data when ProGuard is enabled 【发布时间】:2016-06-01 01:46:14 【问题描述】:

我尝试使用 Retrofit 2 登录我的用户。(基本上是一个带有基本标头的登录 URL 的 GET)它运行良好,但是一旦我对其进行 ProGuard,标头授权就不再发送。 (查看日志输出)

示例代码:

用户模型:

public interface UserService 

    @GET(GET_LOGIN)
    Observable<User> login(@Header("Authorization") String basic);

登录活动:

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)

日志(非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)

完整代码可以在这里找到:https://github.com/supercairos/virtual-passport

【问题讨论】:

我认为主要问题是 proguard 剥离了 @Header("Authorization") 注释。但我不知道为什么。特别是因为我明确告诉他保留 -keepattributes Annotation 【参考方案1】:

我终于成功了。这是关于 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

【讨论】:

对我不起作用...在尝试了这个以及我可能找到的所有其他规则之后仍然遇到同样的错误。链接规则,因为评论太长了。 link 不行,还是不能发送请求参数 是的,我也遇到了同样的问题【参考方案2】:

添加到@Romain 的答案 您需要添加到 proguard 文件中

-keepclasseswithmembers class * 
    @retrofit2.http.* <methods>;

如果你使用@Header,@Query...

参考这里Retrofit2 proguard remove param

【讨论】:

【参考方案3】:

终于找到了。 如果你使用 Gson 就试试这个, 将此添加到改造 pro-guard :

-keepclassmembers,allowobfuscation class * 
  @com.google.gson.annotations.SerializedName <fields>;
 

然后在您的模型中使用@SerializedName("name") .kotlin 示例:

class PaymentRequestModel (
    @SerializedName("name")
    @Expose
    var name : String = "",

【讨论】:

我在改造 json 解析时遇到了问题。当我在发布版本中将 minifyEnabled 更改为 true 时,就会发生这种情况。在 proguard 中添加上述内容解决了我的问题。此外,如果您在改造帖子请求中使用数据类作为请求正文,那么添加 @SerializedName("") 也很重要。 我在请求中使用了 headers、query、post 和 body,当 proguard 启用时,这不起作用,你能告诉我我需要改变什么吗? @Arbaz.in 您应该将您正在使用的所有库的 pro-guards 添加到您的应用程序 pro-guard 中,例如 retrofit 、 Gson 、...。【参考方案4】:

另一个简单的解决方案 使用支持注释中的@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>


【讨论】:

【参考方案5】:

对我来说,使用注释 @SerializedName

public class YourJsonClass
   @SerializedName("name") String username;

   ...
 

【讨论】:

【参考方案6】:

添加 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

【讨论】:

【参考方案7】:

你需要添加

 @SerializedName("yourInputParameter")

在您的请求正文的 bean(model) 类中

例如

 public class YourClass
       @SerializedName("yourInputParameter") String yourInputParameter;

       ...
     

会有用的

因为现在 retrofit 无法读取您的请求正文,因为 proguard(minifyEnabled) 为 true

在您的请求正文中添加 @SerializedName 后,它肯定会为您工作

【讨论】:

【参考方案8】:

将此添加到 progaurd

-keep public class com.data.YOurDataModels.* 
  public void set*(***);
  public *** get*();
  public protected private *;

【讨论】:

【参考方案9】:

只需在您的数据类中添加 @Keep

 @Keep  
    data class ClassPojo(
      @SerializedName("MESSAGE") val message: String,  
      @SerializedName("STATUS") val status: String)

【讨论】:

以上是关于启用 ProGuard 时改造 2 不发送数据的主要内容,如果未能解决你的问题,请参考以下文章

androidx.paging.PagedStorage.init 在启用 proguard 时给出错误

当我使用proguard并启用minify和shrinkresources时,Retrofit body request是空白的

启用 ProGuard 规则时 Gson 解析不起作用

使用 Joda Time 时无法生成启用 proguard 的签名 APK

使用改造发送多部分文件:2.0.0-beta1

Android - Proguard 和改造 2?