致命异常:发布版本中的 java.lang.NullPointerException
Fatal Exception: java.lang.NullPointerException in release build
我在应用程序的发布版本中遇到了一个奇怪的问题。
这是我的例外
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.onChanged (SplashActivity.java:48)
in.hopq.hopq.authentication.activities.SplashActivity$onCreate.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
)
}
}
这是我的混淆文件
##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*
我想,您在 json 字段 min_allowed_version
中收到空值,因为清楚地键入了异常:
Fatal Exception: java.lang.NullPointerException throw with null
exceptionin.hopq.hopq.authentication.models.AppUpdateSourceDO$AppUpdate.getMinAllowedVersion (AppUpdateSourceDO.java:3)
这意味着,当您调用 minAllowedVersion
字段的 getter 及其 returns 空时 - 您捕获了 NPE。尝试使用 null-safety,也许一切都会正常。
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
)
终于解决了这个问题。这是因为新的 R8 代码混淆。只需将其添加到 gradle.properties 文件
即可从您的项目中禁用它
android.enableR8=false
此外,您将其添加到混淆器规则文件中。
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
然而,将其添加到混淆器中并没有真正奏效。
GSON 和 R8 好像不能很好地配合,写的是 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.
此外,您可以在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 ----------
如果 @SerializedName 批注始终用于数据 classes 则可以使用以下保留规则
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
如果不使用@SerializedName 注释,则可以对每个数据使用以下保守规则class:
-keepclassmembers class MyDataClass {
!transient <fields>;
}
有关更多信息,您可以在下面查看link :-
https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md
完全禁用 R8
可能不是一个好主意。但是通过在 Proguard Rules 文件中添加以下行可能会解决问题 --
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
-keep,allowobfuscation @interface com.google.gson.annotations.SerializedName
Google 开发人员之一也建议将此作为所需的解决方案。您可以找到他的答案 here,也可以关注围绕它的整个讨论。
使用 @Keep
注释可以是处理混淆文件的合理替代方法。只需用 @Keep
注释您的数据 class,整个 class 及其成员将不会被缩小。
当所有属性的名称都与json字段的名称匹配并且不需要用@SerializedName
注释属性时,它特别有用。带有 @SerializedName
注释字段(在其他答案中提到)的 classes 的 Proguard 规则不适用于这种情况。
您可能需要使用
-keepclassmembers enum * { *; }
保留您的枚举
在我的例子中,将 android.enableR8=true
添加到我的 gradle.properties 并将 -keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName <fields>; }
添加到我的 proguard-rules.pro 就成功了
我在应用程序的发布版本中遇到了一个奇怪的问题。 这是我的例外
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.onChanged (SplashActivity.java:48)
in.hopq.hopq.authentication.activities.SplashActivity$onCreate.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
)
}
}
这是我的混淆文件
##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*
我想,您在 json 字段 min_allowed_version
中收到空值,因为清楚地键入了异常:
Fatal Exception: java.lang.NullPointerException throw with null
exceptionin.hopq.hopq.authentication.models.AppUpdateSourceDO$AppUpdate.getMinAllowedVersion (AppUpdateSourceDO.java:3)
这意味着,当您调用 minAllowedVersion
字段的 getter 及其 returns 空时 - 您捕获了 NPE。尝试使用 null-safety,也许一切都会正常。
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
)
终于解决了这个问题。这是因为新的 R8 代码混淆。只需将其添加到 gradle.properties 文件
即可从您的项目中禁用它android.enableR8=false
此外,您将其添加到混淆器规则文件中。
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
然而,将其添加到混淆器中并没有真正奏效。
GSON 和 R8 好像不能很好地配合,写的是 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.
此外,您可以在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 ----------
如果 @SerializedName 批注始终用于数据 classes 则可以使用以下保留规则
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
如果不使用@SerializedName 注释,则可以对每个数据使用以下保守规则class:
-keepclassmembers class MyDataClass {
!transient <fields>;
}
有关更多信息,您可以在下面查看link :-
https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md
完全禁用 R8
可能不是一个好主意。但是通过在 Proguard Rules 文件中添加以下行可能会解决问题 --
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
-keep,allowobfuscation @interface com.google.gson.annotations.SerializedName
Google 开发人员之一也建议将此作为所需的解决方案。您可以找到他的答案 here,也可以关注围绕它的整个讨论。
使用 @Keep
注释可以是处理混淆文件的合理替代方法。只需用 @Keep
注释您的数据 class,整个 class 及其成员将不会被缩小。
当所有属性的名称都与json字段的名称匹配并且不需要用@SerializedName
注释属性时,它特别有用。带有 @SerializedName
注释字段(在其他答案中提到)的 classes 的 Proguard 规则不适用于这种情况。
您可能需要使用
-keepclassmembers enum * { *; }
保留您的枚举
在我的例子中,将 android.enableR8=true
添加到我的 gradle.properties 并将 -keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName <fields>; }
添加到我的 proguard-rules.pro 就成功了