Après avoir mis à jour les dépendances vers les dernières versions, nous avons rencontré un problème d'exécution dans les versions publiées en raison d'une implémentation d'interface manquante.
java.lang.IncompatibleClassChangeError:
Class 'com.mypackage.app.data.cache.query.user.QueryUserFollowersCountById'
does not implement interface 'com.mypackage.app.data.cache.query.Query'
in call to 'java.lang.String[] com.mypackage.app.data.cache.query.Query.c()'
(declaration of 'com.mypackage.app.data.cache.database.util.Db'
appears in /data/app/com.mypackage.app-2/base.apk:classes2.dex)
Deux jours de débogage plus tard, nous pensons que le problème est lié au fait que Proguard supprime l'élément "implémente une requête" pendant sa phase de réduction. L'interface elle-même est conservée car elle est utilisée dans des centaines d'autres classes, elle est seulement absente dans 3 classes. Nous avons également trouvé des interfaces RxJava Func0 et Action0 supprimées de la même manière, mais à quelques endroits seulement. Ainsi, l'application fonctionne parfaitement sur 95% des écrans, mais se bloque évidemment là où l'implémentation de l'interface est manquante.
- Nous utilisons la version 3.1.3 des outils de construction Gradle, mais nous avons également essayé avec la version 3.3.0-alpha03, ainsi que la désactivation de D8, donc cela ne devrait pas être un problème lié aux outils de construction (les versions 5.3.3 et 6.0.3 de Proguard se comportent de la même manière dans ce cas).
- Le problème apparaît lorsque l'on fait passer Dagger2 de la version 2.11 à la 2.12 ou à une version ultérieure. Il pourrait donc être lié à la quantité de champs/méthodes/classes, etc. dans l'application.
- Le problème persiste même en utilisant -dontoptimize, nous avons parcouru la documentation de Proguard et activé/désactivé presque tous les drapeaux pertinents.
- Le problème est résolu en mettant minifyEnabled à false ou en utilisant l'option -dontshrink pour Proguard.
- L'application utilise Multidex, les deux constructions avec Dagger 2.11 et Dagger 2.12 se retrouvent avec 3 fichiers classes.dex. L'interface problématique et les implémentations sont dans le même fichier .dex dans les deux cas.
- Par exemple, il y a 5 fichiers dans le même paquet qui implémentent Query, 3 d'entre eux ont l'interface dans le bytecode résultant, mais 2 fichiers ne l'ont pas. Cela ne devrait donc pas être lié à l'endroit où les fichiers sont placés.
Bytecode quand il est construit en utilisant Dagger 2.11 ou -dontshrink
.class public Lcom/mypackage/app/data/cache/query/user/QueryUserFollowersCountById;
.super Ljava/lang/Object;
.source "SourceFile"
# interfaces
.implements Lcom/mypackage/app/data/cache/query/Query;
# annotations
.annotation system Ldalvik/annotation/Signature;
value = {
"Ljava/lang/Object;",
"Lcom/mypackage/app/data/cache/query/Query<",
"Ljava/lang/Integer;",
">;"
}
.end annotation
......
Bytecode lorsqu'il est construit à l'aide de Dagger 2.12 ou d'une version ultérieure
.class public Lcom/mypackage/app/data/cache/query/user/QueryUserFollowersCountById;
.super Ljava/lang/Object;
.source "SourceFile"
# annotations
.annotation system Ldalvik/annotation/Signature;
value = {
"Ljava/lang/Object;"
}
.end annotation
......
Nous voulons évidemment utiliser la dernière version de Dagger2 et continuer à réduire et à optimiser notre code avec Proguard.
- Comment s'assurer que Proguard ne supprimera pas les déclarations de l'interface implements ?
- Ou comment ajouter la journalisation/débogage à l'étape de réduction de Proguard ?