Been working on using retrofit in an android library for a project. While, if configured in the app's gradle or if the source of the library is part of the app project, everything seems to be work well.
But, if the library project is proguarded and included in the app as an @aar. There seems to be a obsfucation issue.
Here's my proguard for retrofit in android module project:
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Exceptions
-keepattributes RuntimeVisibleAnnotations
-keepattributes RuntimeInvisibleAnnotations
-keepattributes RuntimeVisibleParameterAnnotations
-keepattributes RuntimeInvisibleParameterAnnotations
-keepattributes EnclosingMethod
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
-keepclasseswithmembers interface * {
@retrofit2.* <methods>;
}
# 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
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain service method parameters.
-keepclassmembernames,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-keep public interface com.mylibrary.interfaces.**
-keep public class com.mylibrary.rest.RetrofitClientInstance
-keep public class com.mylibrary.models.** {*;}
-dontwarn org.xmlpull.v1.**
-dontwarn javax.annotation.**
### OkHttp3
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
And, this is how my RetrofitClientInstance class look like:
public class RetrofitClientInstance {
private static Retrofit retrofit;
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(Constants.BASE_API_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
And the error that I'm getting:
java.lang.NoClassDefFoundError: Failed resolution of: Lretrofit2/Retrofit$Builder;
at com.mylibrary.rest.RetrofitClientInstance.getRetrofitInstance(RetrofitClientInstance.java:15)
at com.mylibrary.rest.LoginAPIHelper.<init>(LoginAPIHelper.java:29)
at com.mylibrary.rest.LoginAPIHelper.getInstance(LoginAPIHelper.java:36)
at com.view.LoginActivity.onCreate(LoginActivity.java:124)
at android.app.Activity.performCreate(Activity.java:6772)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2715)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2823)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6349)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
Caused by: java.lang.ClassNotFoundException: Didn't find class "retrofit2.Retrofit$Builder" on path: DexPathList[[zip file "/data/app/com.inventaapp-2/base.apk"],nativeLibraryDirectories=[/data/app/com.inventaapp-2/lib/arm, /data/app/com.inventaapp-2/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at com.mylibrary.rest.RetrofitClientInstance.getRetrofitInstance(RetrofitClientInstance.java:15)
at com.mylibrary.rest.LoginAPIHelper.<init>(LoginAPIHelper.java:29)
at com.mylibrary.rest.LoginAPIHelper.getInstance(LoginAPIHelper.java:36)
at com.inventaapp.view.LoginActivity.onCreate(LoginActivity.java:124)
at android.app.Activity.performCreate(Activity.java:6772)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2715)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2823)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6349)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
I've tried multi-dexing the main app that imports the library. Doesn't affect behavior. Infact if the source is imported as a module in the app project, it works without multi-dexing.
Also, if the aar is imported as library. But if I add the retrofit gradle imports in the main project's gradle. It works in that case too.
What am I missing here? Seems similar issue to this: https://github.com/square/retrofit/issues/1811
FYI, my gradle looks like:
implementation 'com.google.code.gson:gson:2.8.2'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.4.0'
Any assistance is much appreciated.
Thanks in advance, Arnab