30

I am facing a weird issue in the release build of the app. Here's my exception

Fatal Exception: java.lang.NullPointerException`
throw with null exception
in.hopq.hopq.authentication.models.AppUpdateSourceDO$AppUpdate.getMinAllowedVersion (AppUpdateSourceDO.java:3)
in.hopq.hopq.authentication.activities.SplashActivity$onCreate$1.onChanged (SplashActivity.java:48)
in.hopq.hopq.authentication.activities.SplashActivity$onCreate$1.onChanged (SplashActivity.java:31)

Pojo File

data class AppUpdateSourceDO(
    @SerializedName("app_update")
    val appUpdate: AppUpdate,
    @SerializedName("message")
    val message: String,
    @SerializedName("success")
    val success: Boolean
) {
data class AppUpdate(
        @SerializedName("excluded_versions")
        val excludedVersions: List<ExcludedVersion>,
        @SerializedName("min_allowed_version")
        val minAllowedVersion: Int,
        @SerializedName("min_allowed_version_ios")
        val minAllowedVersionIos: String,
        @SerializedName("recommended_version")
        val recommendedVersion: Int?
) {
    data class ExcludedVersion(
            @SerializedName("version")
            val version: String
    )
}
}

Here's my proguard file

##OKHTTP3
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontnote okhttp3.**
-dontwarn okio.**
-dontwarn retrofit2.Platform$Java8
# 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*
Sam
  • 40,644
  • 36
  • 176
  • 219
pratham kesarkar
  • 3,770
  • 3
  • 19
  • 29

8 Answers8

29

Finally solved this issue. This is because of the new R8 code obfuscation. Simply disable it from your project by adding this to the gradle.properties file

android.enableR8=false

Additionally you add this to your proguard rules file.

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

However adding this to the proguard didn't really worked out.

pratham kesarkar
  • 3,770
  • 3
  • 19
  • 29
28

Disabling R8 entirely might not be a good idea. But by adding below lines in your Proguard Rules file might solve the issue --

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

This is also suggested by one of the Google developers as the desired solution. You can find his answer here and you can also follow the entire discussion around it.

Abhishek
  • 920
  • 13
  • 23
  • This solution worked for me. I implemented the first solution of this post and I had compilation problem with Dagger and OKHttp3 when building and signing my app for release – Johana Lopez 1327 Mar 18 '20 at 15:48
10

Seems GSON and R8 don't work well together, and it's written about here:

Actually, the following should also work:

-keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName ; } -keep,allowobfuscation @interface com.google.gson.annotations.SerializedName

That will minify (obfuscate) the names of the fields and the attribute as well, to further reduce the size of the final APK.

In addition, you can see the next rules in the sample of Gson:

##---------------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
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }

# 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

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

##---------------End: proguard configuration for Gson  ----------
android developer
  • 114,585
  • 152
  • 739
  • 1,270
3

If the @SerializedName annotation is used consistently for data classes the following keep rule can be used

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

If the @SerializedName annotation is not used the following conservative rule can be used for each data class:

-keepclassmembers class MyDataClass {
  !transient <fields>;
 }

For more info, you can check out below link :-

https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md

Bhaven Shah
  • 692
  • 1
  • 5
  • 18
2

You may need to use

-keepclassmembers enum * { *; }

to keep your enums

Barral
  • 61
  • 4
2

In my case adding android.enableR8=true to my gradle.properties and -keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName <fields>; } to my proguard-rules.pro did the trick

0

I suppose, that you receive null in the json field min_allowed_version because of exception is clearly typed:

Fatal Exception: java.lang.NullPointerException throw with null 
exceptionin.hopq.hopq.authentication.models.AppUpdateSourceDO$AppUpdate.getMinAllowedVersion (AppUpdateSourceDO.java:3)

It means, that when you calling getter of minAllowedVersion field and its returns null - you caught NPE. Try to use null-safety and maybe all will works fine.

data class AppUpdate(
        @SerializedName("excluded_versions")
        val excludedVersions: List<ExcludedVersion> = listOf(),
        @SerializedName("min_allowed_version")
        val minAllowedVersion: Int? = null,
        @SerializedName("min_allowed_version_ios")
        val minAllowedVersionIos: String? = null,
        @SerializedName("recommended_version")
        val recommendedVersion: Int? = null
)
Scrobot
  • 1,911
  • 3
  • 19
  • 36
0

Using @Keep annotation can be a reasonable alternative for dealing with proguard files. Just annotate your data class with @Keep and the whole class with its members won't be minified.

It is especially useful when names of all properties match with names of json fields and there is no need to annotate properties with @SerializedName. Proguard rules for classes with @SerializedName annotated fields (mentioned in other answers) are not applicable to such a case.

art
  • 1,222
  • 9
  • 19