【问题标题】:Fatal Exception: java.lang.NullPointerException in release build致命异常:发布版本中的 java.lang.NullPointerException
【发布时间】:2019-10-02 04:09:33
【问题描述】:

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

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*

【问题讨论】:

    标签: android kotlin gson retrofit android-r8


    【解决方案1】:

    终于解决了这个问题。这是因为新的 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 好像还有这个 bug issuetracker.google.com/issues/120277396希望他们尽快修复。
    • @MehulKabaria 快乐
    • 这样做对代码混淆有好处还是有影响?
    • 很好的答案 kesarkar 先生,但是 enableR8 是什么?
    • @GunduBandgar R8 是谷歌新的代码混淆引擎,类似于 proguard。
    【解决方案2】:

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

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

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

    【讨论】:

    • 这个解决方案对我有用。我实现了这篇文章的第一个解决方案,在构建和签署我的应用程序以进行发布时,我遇到了 Dagger 和 OKHttp3 的编译问题
    • 最后,它对我有用。非常感谢@Abhishek
    【解决方案3】:

    好像GSON和R8不好配合,写的是here

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

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

    这将缩小(混淆)字段和属性的名称 同时,进一步减小最终 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  ----------
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          您可能需要使用

          -keepclassmembers enum * { *; }
          

          保留您的枚举

          【讨论】:

            【解决方案7】:

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

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

            这意味着,当您调用 minAllowedVersion 字段的 getter 并返回 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
            )
            

            【讨论】:

              【解决方案8】:

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2014-04-15
                • 1970-01-01
                • 2015-07-22
                • 1970-01-01
                • 2015-04-11
                • 2019-01-03
                • 1970-01-01
                相关资源
                最近更新 更多