Фатальное исключение: java.lang.NullPointerException в сборке выпуска
Я столкнулся со странной проблемой в сборке релиза приложения. Вот мое исключение
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
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
)
}
}
Вот мой файл proguard
##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*
2 ответа
Наконец-то решили эту проблему. Это из-за новой обфускации кода R8. Просто отключите его в своем проекте, добавив его в файл gradle.properties
android.enableR8=false
Кроме того, вы добавляете это в свой файл правил proguard.
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
Однако добавление этого в proguard не сработало.
Отключение R8
совсем не может быть хорошей идеей. Но добавление следующих строк в файл правил Proguard может решить проблему -
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
-keep,allowobfuscation @interface com.google.gson.annotations.SerializedName
Это также предлагается одним из разработчиков Google в качестве желаемого решения. Вы можете найти его ответ здесь, а также можете следить за всем обсуждением вокруг него.
Кажется, GSON и R8 плохо работают вместе, и об этом написано здесь:
На самом деле, следующее также должно работать:
-kekeclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName; } -keep,allowobfuscation @interface com.google.gson.annotations.SerializedName
Это минимизирует (запутывает) имена полей и атрибута, чтобы еще больше уменьшить размер окончательного APK.
Кроме того, вы можете увидеть следующие правила в образце 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 ----------
Если аннотация @SerializedName используется последовательно для классов данных, можно использовать следующее правило хранения
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
Если аннотация @SerializedName не используется, для каждого класса данных можно использовать следующее консервативное правило:
-keepclassmembers class MyDataClass {
!transient <fields>;
}
Для получения дополнительной информации, вы можете проверить ниже ссылку: -
https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md
Возможно, вам придется использовать
-keepclassmembers enum * { *; }
сохранить ваши перечисления
В моем случае добавление android.enableR8=true
в мои gradle.properties и -keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName <fields>; }
с моим proguard-rules.pro сделали свое дело
Я полагаю, что вы получаете нуль в поле JSON min_allowed_version
из-за исключения четко набирается:
Fatal Exception: java.lang.NullPointerException throw with null
exceptionin.hopq.hopq.authentication.models.AppUpdateSourceDO$AppUpdate.getMinAllowedVersion (AppUpdateSourceDO.java:3)
Это означает, что когда вы звоните minAllowedVersion
поле и его возвращение null - вы поймали NPE. Попробуйте использовать нуль-безопасность, и, возможно, все будет работать нормально.
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
)
С помощью @Keep
аннотации могут быть разумной альтернативой для работы с файлами proguard. Просто аннотируйте свой класс данных с помощью@Keep
и весь класс с его членами не будет минифицирован.
Это особенно полезно, когда имена всех свойств совпадают с именами полей json и нет необходимости аннотировать свойства с помощью @SerializedName
. Правила Proguard для занятий с@SerializedName
аннотированные поля (упомянутые в других ответах) не применимы в таком случае.