Ludovic ROLAND

Blog technique sur mes expériences de développeur.

NoClassDefFoundError: android.support.design.internal.NavigationMenu sur Wiko et Samsung sous Android 4.2.2

17 octobre 2015

Après les problèmes rencontrés sur Wiko et Samsung sous Android 4.2.2 avec l’utilisation de la bibliothèque appcompat-v7 en version 21 je vous propose aujourd’hui d’adresser un problème qui touche une nouvelle fois ces terminaux à cause de l’utilisation de la nouvelle bibliothèque de Google : Android Support Design dans sa version 23.0.1.

Pour rappel, cette bibliothèque permet aux développeurs d’utiliser de nombreux composants graphiques liés au style Material Design dans leurs applications.

Dans ce billet, nous allons voir comment contourner le problème.

Le problème

Si vous utilisez la bibliothèque Android Support Design dans sa version 23.0.1 et plus spécifiquement le composant NavigationMenu dans l’un de vos layout et que vous exécutez votre application sur un téléphone Wiko sous Android 4.2.2, vous devriez voir votre application planter et le message d’erreur suivant s’afficher dans le logcat :

java.lang.RuntimeException: Unable to start activity ComponentInfo{applicationId/package.MainActivity}: android.view.InflateException: Binary XML file line #11: Error inflating class <unknown>
[...]
Caused by: android.view.InflateException: Binary XML file line #11: Error inflating class <unknown> 
Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Constructor.constructNative(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
        at android.view.LayoutInflater.createView(LayoutInflater.java:587)
[...]
Caused by: java.lang.NoClassDefFoundError: android.support.design.internal.NavigationMenu
        at android.support.design.widget.NavigationView.<init>(NavigationView.java:99)
        at android.support.design.widget.NavigationView.<init>(NavigationView.java:92)
        at java.lang.reflect.Constructor.constructNative(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
        at android.view.LayoutInflater.createView(LayoutInflater.java:587)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
[...]

Comme vous pouvez le constater, la classe NavigationMenu n’est pas trouvée par le téléphone.

La solution

Comme pour le précédent problème qui touchaient ces terminaux, la solution consiste à utiliser Proguard et écrire quelques règles spécifiques. Aussi, dans le fichier proguard-rules.pro de votre projet (si ce fichier n’existe pas créez le), écrivez les lignes suivantes :

-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

-dontobfuscate
-dontoptimize
-repackageclasses ''

#Android
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.app.** { *; }
-keep interface android.support.v7.app.** { *; }
-keep class android.support.v13.app.** { *; }
-keep interface android.support.v13.app.** { *; }

#my app
-keep class my.app.package.** { *; }

Rendez-vous ensuite dans votre fichier build.gradle et plus précisément dans la section buildTypes pour activer l’utilisation du fichier au moment de la compilation de votre projet :

buildTypes 
{
  release 
  {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  }
  debug 
  {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  }
}

Si vous utilisez des bibliothèques externes comme par exemple Jackson ou Critercism il n’est pas impossible que vous ayez des warnings à la compilation ou des crashs à l’exécution de votre appplication.

Vous pouvez ignorer les warnings en ajoutant des règles spécifiques dans le fichier proguard-rules.pro. Par exemple, pour ignorer les warnings liés à Jackson, vous pouvez ajouter la règle suivante :

-dontwarn com.fasterxml.**

Pour les crashs, il conviendra d’ajouter des règles spécifiques à la bibliothèque qui pose soucis. Par exemple pour Critercism :

-keep public class com.crittercism.**
-keepclassmembers public class com.crittercism.* { *; }

Aussi, votre fichier proguard-rules.pro devrait alors ressembler à ça :

-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

-dontobfuscate
-dontoptimize
-repackageclasses ''

#Jackson
-dontwarn com.fasterxml.jackson.databind.**

#Android
-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.app.** { *; }
-keep interface android.support.v7.app.** { *; }
-keep class android.support.v13.app.** { *; }
-keep interface android.support.v13.app.** { *; }

#my app
-keep class my.app.package.** { *; }

#Critercism
-keep public class com.crittercism.**
-keepclassmembers public class com.crittercism.* { *; }

Commentaires