web-dev-qa-db-ja.com

致命的な例外:リリースビルドでの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)

ポージョファイル

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

最後にこの問題を解決しました。これは、新しいR8コードの難読化が原因です。これをgradle.propertiesファイルに追加して、プロジェクトから無効にしてください

Android.enableR8=false

さらに、これをプロガードルールファイルに追加します。

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

しかし、これをプロガードに追加しても、うまくいきませんでした。

22

無効にするR8完全に良いアイデアではないかもしれません。しかし、Proguard Rulesファイルに以下の行を追加すると、問題が解決する可能性があります-

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

これは、Googleの開発者の1人からも望ましい解決策として提案されています。あなたは彼の答えを見つけることができます ここ そしてあなたはそれについての全体の議論に従うこともできます。

8
Abhishek

GSONとR8は一緒にうまく動作しないようです、そしてそれは here について書かれています:

実際には、以下も機能するはずです。

-keepclassmembers、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  ----------
6

@Keep アノテーションを使用することは、proguardファイルを処理するための合理的な代替手段となります。データクラスに@Keepの注釈を付けるだけで、クラス全体とそのメンバーが縮小されません。

すべてのプロパティの名前がjsonフィールドの名前と一致し、@SerializedNameでプロパティに注釈を付ける必要がない場合に特に便利です。 @SerializedName注釈付きフィールド(他の回答で説明)を持つクラスのProguardルールは、このような場合には適用されません。

1
art

例外が明確に入力されているため、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フィールドのゲッターを呼び出し、そのフィールドがnullを返す場合、NPEを検出しました。 nullセーフを使用してみてください。多分すべてが正常に動作します。

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
)
1
Scrobot

使用する必要があるかもしれません

-keepclassmembers enum * { *; }

あなたの列挙を維持する

0
Barral

@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

0
Bhaven Shah