27

I try to login my users using Retrofit 2. (Basically a GET to the login URL with a basic header) It works well but once I ProGuard it, the Header Authorization is not sent anymore. (See log outputs)

Sample code :

User Model :

public interface UserService {

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

Login 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 File :

# Retrofit
-dontwarn retrofit2.** 
-dontwarn org.codehaus.mojo.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepattributes *Annotation*
-keepclasseswithmembers class * {
    @retrofit.* <methods>;
}

-keepclasseswithmembers interface * {
    @retrofit.* <methods>;
}

Logs (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)

Logs (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)

Full code can be found here : https://github.com/supercairos/virtual-passport

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Romain
  • 1,390
  • 1
  • 13
  • 27
  • I think the main problem is that proguard strip the @Header("Authorization") annotation. But i have no idea why. Especially since I explicitly told him to keep -keepattributes *Annotation* – Romain Feb 19 '16 at 13:18

9 Answers9

44

I finally managed to make it work. Here is the proguard configuration regarding Retrofit 2

# 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>;
}

Thanks @xudshen

UPDATE

The main problem: I used proguard-android-optimize So I should added:

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

I also switched back to the regular Retrofit 2 proguard config provided by square :

# 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
Community
  • 1
  • 1
Romain
  • 1,390
  • 1
  • 13
  • 27
  • Didn't work for me...still got the same error after trying this and all the other rules i could possibly find. Linked the rules since it's too long for the comment. [link](https://docs.google.com/document/d/1wXa0Y-IWQ34nO7E4DdqFDj9_hXMXkBDXFRcPV9u0Z4c/edit?usp=sharing) – stewie Oct 30 '16 at 14:47
  • Not working, I am still not able to send request parameters – Shivang Jan 13 '17 at 09:45
  • Yeah me too getting same problem – Mansuu.... May 11 '17 at 12:03
12

Adding to @Romain's answer You Need to add to proguard file

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

If you are using @Header, @Query...

Reference from here Retrofit2 proguard remove param

Community
  • 1
  • 1
silentsudo
  • 6,730
  • 6
  • 39
  • 81
11

finally i find. just try this if you use Gson , add this to retrofit pro-guard :

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

then use @SerializedName("name") in your model .kotlin example:

class PaymentRequestModel (
    @SerializedName("name")
    @Expose
    var name : String = "",
}
mhKarami
  • 844
  • 11
  • 16
  • I was facing issue in retrofit json parsing. This happened when I change minifyEnabled to true in release build. adding the above in line proguard fixed my issue. Also If you use data class for request body in retrofit post requests, then adding @SerializedName("") is also important. – Kalaiselvan Sep 04 '20 at 13:46
  • i used headers,query,post and body for request and that is not working when proguard is enable can you please tell me what i have to change? – Arbaz.in Jan 15 '21 at 01:51
  • 1
    @Arbaz.in you should add pro-guards of all libraries you are using to your app pro-guard for example retrofit , Gson ,.. . – mhKarami Jan 15 '21 at 18:17
9

Another simple solution use @keep from support annotation 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>

}
Pauland
  • 1,974
  • 16
  • 25
6

for me works using annotation @SerializedName

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

   ...
 }
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Peter
  • 260
  • 5
  • 3
1

Add this to progaurd

-keep public class com.data.YOurDataModels.* {
  public void set*(***);
  public *** get*();
  public protected private *;
}
John Conde
  • 217,595
  • 99
  • 455
  • 496
akkmastr
  • 186
  • 6
1

Just Add @Keep on your data class

 @Keep  
    data class ClassPojo(
      @SerializedName("MESSAGE") val message: String,  
      @SerializedName("STATUS") val status: String)
Harman Khera
  • 236
  • 2
  • 9
0

Add Retrofit 2 compatibility with Proguard code Obfuscator

    -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
Duna
  • 1,564
  • 1
  • 16
  • 36
0

You need to add

 @SerializedName("yourInputParameter")

in your bean(model) class for your request body

For example

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

       ...
     }

it will work

because now retrofit unable to read your request body because proguard(minifyEnabled) is true

after adding @SerializedName in your request body it will definitely work for you

Amit Desale
  • 1,281
  • 3
  • 16
  • 43