J'ai développé une application Android, en utilisant Moshi comme l'une de ses dépendances.
Aujourd'hui, je souhaite activer minify pour ce projet. J'ai donc défini minifyEnabled true
dans mon build.gradle
.
Après cela, j'ai constaté que toutes les réponses du serveur devenaient nulles.
Tout d'abord, j'utilise Retrofit2 pour appeler des API. Le corps JSON dans Response.body()
n'est pas nul et a des valeurs correctes.
Le corps de la réponse est comme ci-dessous (simplifié):
# Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: -keepclassmembers class fqcn.of.javascript.interface.for.webview { public *; } # Uncomment this to preserve the line number information for # debugging stack traces. -keepattributes SourceFile,LineNumberTable, *Annotation* # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile #Crashlytics: https://docs.fabric.io/android/crashlytics/dex-and-proguard.html -keepattributes *Annotation* -keep public class * extends java.lang.Exception #https://stackoverflow.com/questions/36816521/is-the-format-of-the-data-held-in-kotlin-metadata-documented-anywhere -dontwarn kotlin.** -dontwarn kotlin.reflect.jvm.internal.** -keep class kotlin.reflect.jvm.internal.** { *; } -keep class kotlin.Metadata { *; } -keepclassmembers public class com.example.app.** { public synthetic <methods>; } -keepclassmembers class kotlin.Metadata { public <methods>; } -keepclassmembers class **$WhenMappings { <fields>; } -keep class kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoaderImpl #All models -keep class com.example.app.models.** #######Retrofit####### #https://github.com/square/retrofit/blob/master/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro # Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and # EnclosingMethod is required to use InnerClasses. -keepattributes Signature, InnerClasses, EnclosingMethod # Retrofit does reflection on method and parameter annotations. -keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations # Retain service method parameters when optimizing. -keepclassmembers,allowshrinking,allowobfuscation interface * { @retrofit2.http.* <methods>; } # Ignore annotation used for build tooling. -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement # Ignore JSR 305 annotations for embedding nullability information. -dontwarn javax.annotation.** # Guarded by a NoClassDefFoundError try/catch and only used when on the classpath. -dontwarn kotlin.Unit # Top-level functions that can only be used by Kotlin. -dontwarn retrofit2.KotlinExtensions # With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy # and replaces all potential values with null. Explicitly keeping the interfaces prevents this. -if interface * { @retrofit2.http.* <methods>; } -keep,allowobfuscation interface <1> #######OkHttp3###### #https://github.com/square/okhttp/blob/master/okhttp/src/main/resources/META-INF/proguard/okhttp3.pro # JSR 305 annotations are for embedding nullability information. -dontwarn javax.annotation.** # A resource is loaded with a relative path so the package of this class must be preserved. -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. -dontwarn org.codehaus.mojo.animal_sniffer.* # OkHttp platform used only on JVM and when Conscrypt dependency is available. -dontwarn okhttp3.internal.platform.ConscryptPlatform ######Okio###### #https://github.com/square/okio/blob/master/okio/src/jvmMain/resources/META-INF/proguard/okio.pro # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. -dontwarn org.codehaus.mojo.animal_sniffer.* ####Moshi#### #https://github.com/square/moshi/blob/master/moshi/src/main/resources/META-INF/proguard/moshi.pro #https://github.com/square/moshi/blob/master/kotlin/reflect/src/main/resources/META-INF/proguard/moshi-kotlin.pro # JSR 305 annotations are for embedding nullability information. -dontwarn javax.annotation.** -keepclasseswithmembers class * { @com.squareup.moshi.* <methods>; } -keep @com.squareup.moshi.JsonQualifier interface * # Enum field names are used by the integrated EnumJsonAdapter. # Annotate enums with @JsonClass(generateAdapter = false) to use them with Moshi. -keepclassmembers @com.squareup.moshi.JsonClass class * extends java.lang.Enum { <fields>; } # The name of @JsonClass types is used to look up the generated adapter. -keepnames @com.squareup.moshi.JsonClass class * # Retain generated JsonAdapters if annotated type is retained. -if @com.squareup.moshi.JsonClass class * -keep class <1>JsonAdapter { <init>(...); <fields>; } -if @com.squareup.moshi.JsonClass class **$* -keep class <1>_<2>JsonAdapter { <init>(...); <fields>; } -if @com.squareup.moshi.JsonClass class **$*$* -keep class <1>_<2>_<3>JsonAdapter { <init>(...); <fields>; } -if @com.squareup.moshi.JsonClass class **$*$*$* -keep class <1>_<2>_<3>_<4>JsonAdapter { <init>(...); <fields>; } -if @com.squareup.moshi.JsonClass class **$*$*$*$* -keep class <1>_<2>_<3>_<4>_<5>JsonAdapter { <init>(...); <fields>; } -if @com.squareup.moshi.JsonClass class **$*$*$*$*$* -keep class <1>_<2>_<3>_<4>_<5>_<6>JsonAdapter { <init>(...); <fields>; } -keep class kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoaderImpl -keepclassmembers class kotlin.Metadata { public <methods>; } ####Mp4 Marser#### -keep class com.coremedia.iso.** {*;} -keep class com.googlecode.mp4parser.** {*;} -keep class com.mp4parser.** {*;} -dontwarn com.coremedia.** -dontwarn com.googlecode.mp4parser.** ####Picasso##### #https://github.com/square/picasso/blob/master/picasso/consumer-proguard-rules.txt # Platform calls Class.forName on types which do not exist on Android to determine platform. -dontnote okhttp3.internal.Platform # java.nio.file.* usage which cannot be used at runtime. Animal sniffer annotation. -dontwarn okio.Okio # JDK 7-only method which is @hide on Android. Animal sniffer annotation. -dontwarn okio.DeflaterSink #Ignore all other 3rd party libraries for now as we don't really care about the size but more about code obfuscation. -keep class de.hdodenhof.** -keep class io.github.luizgrp.sectionedrecyclerviewadapter.** -keep class q.rorbin.badgeview.** -keep class com.theartofdev.edmodo.** -keep class me.relex -keep class com.tbruyelle.rxpermissions2.** -keep class com.github.pwittchen.reactivenetwork.** -keep class com.minimize.android.rxrecycleradapter.** -keep class at.blogc.android.** -keep class com.yarolegovich.** -keep class cn.trinea.android.view.autoscrollviewpager.** -keep class com.apkfuns.logutils.**
Et j'utilise le code ci-dessous pour le convertir en mon propre objet:
class SomeResponse { @Json(name="status") var status: String? = null @Json(name="data") var data: User? = null }
Alors que le code pour SomeResponse
:
val someResponse = Moshi.Builder().add(KotlinJsonAdapterFactory()).build().adapter(SomeResponse::class.java).fromJson(theJsonString)
Et puis j'utilise simplement Log.i("Moshi", "${someResponse.status}"
pour voir la valeur, et le résultat est null
.
J'ai déjà inclus les règles proguard spécifiées dans la section README de Moshi Github, qui est celle-ci et celle-ci .
Pourquoi et comment résoudre ce problème?
Pour référence, proguard-rules.pro
mon proguard-rules.pro
complet:
{"status":"success","data":{"user": "I am a user"}}
5 Réponses :
Je pense que la solution ici est simple: ajoutez un @Keep - Anotation à votre modèle (SomeResponse), ainsi les noms de marshalling ne devraient plus être obscurcis. :-)
Essayez de l'ajouter à votre fichier proguard-rules.pro. J'espère que cela aidera.
# Moshi -keepclassmembers class ** { @com.squareup.moshi.FromJson *; @com.squareup.moshi.ToJson *; }
-keepclasseswithmembers class * { @com.squareup.moshi.* <methods>; } -keep @com.squareup.moshi.JsonQualifier interface * -dontwarn org.jetbrains.annotations.** -keep class kotlin.Metadata { *; } -keepclassmembers class kotlin.Metadata { public <methods>; } -keepclassmembers class * { @com.squareup.moshi.FromJson <methods>; @com.squareup.moshi.ToJson <methods>; } -keepnames @kotlin.Metadata class (Change with Yourpackagename) com.myapp.packagename.model.** -keep class (Change with Yourpackagename) com.myapp.packagnename.model.** { *; } -keepclassmembers class (Change with Yourpackagename) com.myapp.packagename.model.** { *; } Change com.myapp.packagnename to your packagename ORReplace moshi-kotlin with kotshi which plays fine with Proguard without special rules, dropping hundreds of kilobytes in the final apk.
La seule solution qui a fonctionné pour moi est mentionnée dans le commentaire de @JeganBabu
ie Changer @Json(name="field_name")
en @field:Json(name="field_name")
.
La raison est probablement que l'annotation n'est pas appliquée au code Java converti si le field:
n'a pas été ajouté. Assez bizarre.
Pour votre référence: (Moshi in kotlin) @Json vs @field: Json
Vous pouvez également utiliser le processeur d'annotations Moshi "codegen".
Ajoutez la dépendance:
@JsonClass(generateAdapter = false) enum class MyEnumClass { ... }
Puis @JsonClass
vos modèles avec @JsonClass
:
@JsonClass(generateAdapter = true) data class MyModel(...)
Vous devez également annoter toutes les classes enum utilisées par les modèles, mais elles n'ont pas besoin d'adaptateur:
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.9.2"
Les règles Moshi Proguard précédemment mentionnées ici et ici sont également requises.
Le readme a une section pour proguard (vers le bas) sur GitHub: github.com/square/moshi/blob/master/README.md avez-vous implémenté cela?
@MarkKeen Oui, je viens de mettre à jour ma question. Merci quand même
Conservez l'annotation des métadonnées de Kotlin. C'est tout ce qui devrait être nécessaire. Jake Wharton
@coroutineDispatcher J'ai cherché sur Google et essayé la solution ici: medium.com/@AthorNZ/ ... Mais je le résultat est le même. Est-ce que cet article est ce que vous voulez dire?
@SiraLam quel est le package de
SomeResponse
?@BartekLipinski
com.example.app.models
Je soupçonne votre règle pour le modèle. Pouvez-vous essayer d'utiliser
-keep class com.example.app.models.** { *; }
?J'ai eu un problème pour obtenir une valeur nulle lors de l'analyse de json avec moshi dans kotlin. Je l'ai résolu en utilisant @field: Json (name = "") au lieu de @Json (name = ""). Voyez si cela aide.
@BartekLipinski Désolé, j'étais en vacances la semaine dernière. J'ai juste essayé d'ajouter
{ *; }
, mais pas de chance.