29

我在应用程序的发布版本中遇到了一个奇怪的问题。这是我的例外

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*
4

8 回答 8

30

终于解决了这个问题。这是因为新的 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 并没有真正奏效。

于 2019-05-15T12:16:01.370 回答
27

完全禁用R8可能不是一个好主意。但是通过在您的Proguard 规则文件中添加以下行可能会解决问题 -

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

一位 Google 开发人员也建议将其作为所需的解决方案。你可以在这里找到他的答案,也可以关注围绕它的整个讨论。

于 2019-09-12T09:56:41.220 回答
9

似乎 GSON 和 R8 不能很好地协同工作,它写在这里

实际上,以下内容也应该起作用:

-keepclassmembers,allowobfuscation 类 * { @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  ----------
于 2019-07-03T09:09:21.357 回答
3

如果 @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

于 2019-07-25T05:35:59.383 回答
2

在我的情况下,添加android.enableR8=true到我的 gradle.properties 和-keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName <fields>; }我的 proguard-rules.pro 就可以了

于 2020-09-03T12:00:23.953 回答
1

您可能需要使用

-keepclassmembers enum * { *; }

保留你的枚举

于 2020-03-02T20:35:09.693 回答
0

min_allowed_version我想,由于明确输入了异常,您在 json 字段中收到 null :

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

这意味着,当您调用 getter of minAllowedVersionfield 并返回 null 时,您捕获了 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
)
于 2019-05-15T05:56:22.863 回答
0

使用@Keep注解可能是处理 proguard 文件的合理替代方案。只需注释您的数据类,@Keep整个类及其成员就不会被缩小。

当所有属性的名称都与 json 字段的名称匹配并且不需要使用@SerializedName. 带有注释字段的类的 Proguard 规则@SerializedName(在其他答案中提到)不适用于这种情况。

于 2019-12-19T16:19:34.260 回答