Comment supprimer tous les appels de journalisation de débogage avant de publier l’application sur Google Play?

Selon Google, je dois ” désactiver tous les appels aux méthodes du journal dans le code source ” avant de publier mon application Android. Extrait de la section 5 de la liste de contrôle de publication :

Assurez-vous de désactiver la journalisation et de désactiver l’option de débogage avant de créer votre application pour publication. Vous pouvez désactiver la journalisation en supprimant les appels aux méthodes Log de vos fichiers sources.

Mon projet open source est volumineux et il est difficile de le faire manuellement chaque fois que je le libère. En outre, la suppression d’une ligne de journal est potentiellement délicate, par exemple:

if(condition) Log.d(LOG_TAG, "Something"); data.load(); data.show(); 

Si je commente la ligne Log, alors la condition s’applique à la ligne suivante, et les chances sont que load () n’est pas appelé. Ces situations sont-elles assez rares pour que je puisse décider que cela ne devrait pas exister?

Ceci est sur la liste de contrôle officielle, donc je suppose que beaucoup de gens le font régulièrement.
Alors, comment supprimer efficacement mais en toute sécurité toutes les lignes de journal?

Je trouve qu’une solution beaucoup plus facile consiste à oublier tous les contrôles if et à utiliser ProGuard pour supprimer tous les appels de méthode Log.d() ou Log.v() lorsque nous appelons notre cible de release Ant.

De cette manière, les informations de débogage sont toujours générées pour les versions standard et ne nécessitent aucune modification de code pour les versions de publication. ProGuard peut également effectuer plusieurs passages sur le bytecode pour supprimer d’autres instructions non souhaitées, vider des blocs et mettre automatiquement en place des méthodes courtes, le cas échéant.

Par exemple, voici une configuration ProGuard très basique pour Android:

 -dontskipnonpubliclibraryclasses -dontobfuscate -forceprocessing -optimizationpasses 5 -keep class * extends android.app.Activity -assumenosideeffects class android.util.Log { public static *** d(...); public static *** v(...); } 

Ainsi, vous sauvegardez cela dans un fichier, puis appelez ProGuard depuis Ant, en transmettant votre JAR que vous venez de comstackr et le JAR de la plate-forme Android que vous utilisez.

Voir aussi les exemples du manuel ProGuard.


Mise à jour (4,5 ans plus tard): Aujourd’hui, j’ai utilisé Timber pour la journalisation Android.

Non seulement c’est un peu plus intéressant que l’implémentation de Log par défaut – la balise de journal est définie automatiquement et il est facile d’enregistrer les chaînes et les exceptions formatées – mais vous pouvez également spécifier différents comportements de journalisation à l’exécution.

Dans cet exemple, les instructions de consignation seront uniquement écrites dans logcat dans les versions de débogage de mon application:

Timber est configuré dans ma onCreate() Application onCreate() :

 if (BuildConfig.DEBUG) { Timber.plant(new Timber.DebugTree()); } 

Alors, n’importe où ailleurs dans mon code, je peux facilement me connecter:

 Timber.d("Downloading URL: %s", url); try { // ... } catch (IOException ioe) { Timber.e(ioe, "Bad things happened!"); } 

Reportez-vous à l’ exemple d’application Timber pour un exemple plus avancé, où toutes les instructions de journal sont envoyées à logcat pendant le développement et, en production, aucune instruction de débogage n’est consignée, mais les erreurs sont signalées silencieusement à Crashlytics.

Toutes les bonnes réponses, mais quand j’ai terminé mon développement, je ne voulais ni utiliser les instructions if pour tous les appels de journal, ni utiliser des outils externes.

Donc, la solution que j’utilise est de remplacer la classe android.util.Log par ma propre classe Log:

 public class Log { static final boolean LOG = false; public static void i(Ssortingng tag, Ssortingng ssortingng) { if (LOG) android.util.Log.i(tag, ssortingng); } public static void e(Ssortingng tag, Ssortingng ssortingng) { if (LOG) android.util.Log.e(tag, ssortingng); } public static void d(Ssortingng tag, Ssortingng ssortingng) { if (LOG) android.util.Log.d(tag, ssortingng); } public static void v(Ssortingng tag, Ssortingng ssortingng) { if (LOG) android.util.Log.v(tag, ssortingng); } public static void w(Ssortingng tag, Ssortingng ssortingng) { if (LOG) android.util.Log.w(tag, ssortingng); } } 

La seule chose que je devais faire dans tous les fichiers sources était de remplacer l’importation de android.util.Log par ma propre classe.

Je suggère d’avoir un booléen statique quelque part indiquant s’il faut ou non se connecter:

 classe MyDebug {
   static booléen final LOG = true;
 }

Alors, où que vous souhaitiez vous connecter, il vous suffit de faire ceci:

 if (MyDebug.LOG) {
   if (condition) Log.i (...);
 }

Maintenant, lorsque vous définissez MyDebug.LOG sur false, le compilateur supprimera tout le code à l’intérieur de ces vérifications (car il s’agit d’une finale statique, il sait au moment de la compilation que ce code n’est pas utilisé).

Pour les projets plus importants, vous pouvez commencer à avoir des booléens dans des fichiers individuels pour pouvoir facilement activer ou désactiver la journalisation là où vous en avez besoin. Par exemple, ce sont les différentes constantes de journalisation que nous avons dans le gestionnaire de fenêtres:

 static final Ssortingng TAG = "WindowManager"; static final boolean DEBUG = false; static final boolean DEBUG_FOCUS = false; static final boolean DEBUG_ANIM = false; static final boolean DEBUG_LAYOUT = false; static final boolean DEBUG_RESIZE = false; static final boolean DEBUG_LAYERS = false; static final boolean DEBUG_INPUT = false; static final boolean DEBUG_INPUT_METHOD = false; static final boolean DEBUG_VISIBILITY = false; static final boolean DEBUG_WINDOW_MOVEMENT = false; static final boolean DEBUG_ORIENTATION = false; static final boolean DEBUG_APP_TRANSITIONS = false; static final boolean DEBUG_STARTING_WINDOW = false; static final boolean DEBUG_REORDER = false; static final boolean DEBUG_WALLPAPER = false; static final boolean SHOW_TRANSACTIONS = false; static final boolean HIDE_STACK_CRAWLS = true; static final boolean MEASURE_LATENCY = false; 

Avec le code correspondant comme:

  if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v( TAG, "Adding window " + window + " at " + (i+1) + " of " + mWindows.size() + " (after " + pos + ")"); 

La solution Proguard de Christopher est la meilleure, mais si pour une raison quelconque vous n’aimez pas Proguard, voici une solution très peu technologique:

Journaux de commentaires:

 find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/Log\./;\/\/ Log\./g' 

Décommenter les journaux:

 find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/;\/\/ Log\./Log\./g' 

Une contrainte est que vos instructions de journalisation ne doivent pas s’étendre sur plusieurs lignes.

(Exécutez ces lignes dans un shell UNIX à la racine de votre projet. Si vous utilisez Windows, obtenez une couche UNIX ou utilisez des commandes Windows équivalentes)

Je souhaiterais append quelques précisions sur l’utilisation de Proguard avec Android Studio et sur la graduation, car j’ai eu beaucoup de problèmes pour supprimer les lignes de journal du binary final.

Afin de faire des assumenosideeffects sur les travaux de Proguard, il existe une condition préalable.

Dans votre fichier de graduation, vous devez spécifier l’utilisation de proguard-android-optimize.txt comme fichier par défaut.

 buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' // With the file below, it does not work! //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } 

En fait, dans le proguard-android.txt par défaut proguard-android.txt , l’optimisation est désactivée avec les deux indicateurs:

 -dontoptimize -dontpreverify 

Le proguard-android-optimize.txt n’ajoute pas ces lignes, donc maintenant les assumenosideeffects peuvent fonctionner.

Ensuite, personnellement, j’utilise SLF4J , d’autant plus que je développe des bibliothèques dissortingbuées à d’autres. L’avantage est que, par défaut, il n’y a pas de sortie. Et si l’intégrateur veut des sorties de journal, il peut utiliser Logback pour Android et activer les journaux, afin que les journaux puissent être redirigés vers un fichier ou vers LogCat.

Si j’ai vraiment besoin de supprimer les journaux de la bibliothèque finale, j’ajoute alors à mon fichier Proguard (après avoir activé le proguard-android-optimize.txt bien sûr):

 -assumenosideeffects class * implements org.slf4j.Logger { public *** trace(...); public *** debug(...); public *** info(...); public *** warn(...); public *** error(...); } 

J’ai utilisé une classe LogUtils comme dans l’exemple d’application Google IO. J’ai modifié cela pour utiliser une constante DEBUG spécifique à l’application au lieu de BuildConfig.DEBUG car BuildConfig.DEBUG n’est pas fiable . Ensuite, dans mes cours, j’ai les éléments suivants.

 import static my.app.util.LogUtils.makeLogTag; import static my.app.util.LogUtils.LOGV; public class MyActivity extends FragmentActivity { private static final Ssortingng TAG = makeLogTag(MyActivity.class); protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LOGV(TAG, "my message"); } } 

J’envisagerais d’utiliser la fonction de journalisation de roboguice au lieu du fichier android.util.Log intégré

Leur installation désactive automatiquement les journaux de débogage et de verbose pour les versions de publication. De plus, vous obtenez gratuitement des fonctionnalités intéressantes (par exemple, comportement de journalisation personnalisable, données supplémentaires pour chaque journal, etc.).

Utiliser proguard peut être assez compliqué et je ne voudrais pas passer par la configuration et le faire fonctionner avec votre application, à moins que vous ayez une bonne raison (désactiver les journaux).

Par android.util.Log fournit un moyen d’activer / désactiver le journal:

 public static native boolean isLoggable(Ssortingng tag, int level); 

Par défaut, la méthode isLoggable (…) renvoie false, uniquement après que setprop dans device aime ceci:

 adb shell setprop log.tag.MyAppTag DEBUG 

Cela signifie que tout journal au-dessus du niveau DEBUG peut être imprimé. Référence Android doc:

Vérifie si un journal pour la balise spécifiée est loggable au niveau spécifié. Le niveau par défaut de toute balise est défini sur INFO. Cela signifie que tout niveau supérieur et incluant INFO sera enregistré. Avant de passer des appels à une méthode de journalisation, vérifiez si votre tag doit être enregistré. Vous pouvez modifier le niveau par défaut en définissant une propriété système: ‘setprop log.tag. «Où niveau est soit VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT ou SUPPRESS. SUPPRESS désactivera tous les enregistrements pour votre tag. Vous pouvez également créer un fichier local.prop contenant les éléments suivants: ‘log.tag. =’ Et le placer dans /data/local.prop.

Nous pourrions donc utiliser un utilitaire de journalisation personnalisé:

 public final class Dlog { public static void v(Ssortingng tag, Ssortingng msg) { if (Log.isLoggable(tag, Log.VERBOSE)) Log.v(tag, msg); } public static void d(Ssortingng tag, Ssortingng msg) { if (Log.isLoggable(tag, Log.DEBUG)) Log.d(tag, msg); } public static void i(Ssortingng tag, Ssortingng msg) { if (Log.isLoggable(tag, Log.INFO)) Log.i(tag, msg); } public static void w(Ssortingng tag, Ssortingng msg) { if (Log.isLoggable(tag, Log.WARN)) Log.w(tag, msg); } public static void e(Ssortingng tag, Ssortingng msg) { if (Log.isLoggable(tag, Log.ERROR)) Log.e(tag, msg); } } 

Je suggère fortement d’utiliser Timber de Jake Wharton

https://github.com/JakeWharton/timber

il résout votre problème avec l’activation / désactivation et ajoute automatiquement la classe de balise

juste

 public class MyApp extends Application { public void onCreate() { super.onCreate(); //Timber if (BuildConfig.DEBUG) { Timber.plant(new DebugTree()); } ... 

les journaux ne seront utilisés que dans votre ver de débogage, puis utiliseront

 Timber.d("lol"); 

ou

 Timber.i("lol says %s","lol"); 

imprimer

“Votre classe / msg” sans spécifier la balise

Je publie cette solution qui s’applique spécifiquement aux utilisateurs d’Android Studio. J’ai également récemment découvert Timber et l’ai importé avec succès dans mon application en procédant comme suit:

Placez la dernière version de la bibliothèque dans votre build.gradle:

 comstack 'com.jakewharton.timber:timber:4.1.1' 

Ensuite, dans Android Studios, allez dans Modifier -> Rechercher -> Remplacer dans le chemin …

Tapez dans Log.e(TAG, ou cependant vous avez défini vos messages de journal dans la zone de "Text to find" . Vous venez de la remplacer par Timber.e(

entrer la description de l'image ici

Cliquez sur Rechercher, puis remplacez tout.

Android Studios va maintenant parcourir tous vos fichiers dans votre projet et remplacer tous les journaux par Timbers.

Le seul problème que j’ai rencontré avec cette méthode est que Gradle contient des millions de messages d’erreur par la suite car il ne trouve pas “Timber” dans les importations pour chacun de vos fichiers Java. Il suffit de cliquer sur les erreurs et Android Studios importera automatiquement “Timber” dans votre Java. Une fois que vous l’avez fait pour tous vos fichiers d’erreurs, gradle comstackra à nouveau.

Vous devez également mettre ce morceau de code dans votre méthode onCreate de votre classe Application :

  if (BuildConfig.DEBUG) { Timber.plant(new Timber.DebugTree()); } 

Cela se traduira par la connexion de l’application uniquement lorsque vous êtes en mode de développement pas en production. Vous pouvez également avoir BuildConfig.RELEASE pour vous connecter en mode de publication.

Si vous pouvez exécuter un remplacement global (une fois) et conserver ensuite une convention de codage, vous pouvez suivre le modèle souvent utilisé dans le framework Android.

Au lieu d’écrire

 Log.d(TAG, ssortingng1 + ssortingng2 + arg3.toSsortingng()); 

l’avoir comme

 if (BuildConfig.DEBUG) Log.d(TAG, ssortingng1 + Ssortingng.format("%.2f", arg2) + arg3.toSsortingng()); 

Maintenant, proguard peut supprimer le SsortingngBuilder et toutes les chaînes et méthodes qu’il utilise sur la route, à partir de la version optimisée DEX. Utilisez proguard-android-optimize.txt et vous n’avez pas à vous soucier d’ android.util.Log dans votre proguard-rules.pro :

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

Avec Android Studio gradle plugin, BuildConfig. DEBUG BuildConfig. DEBUG est assez fiable, vous n’avez donc pas besoin de constantes supplémentaires pour contrôler le décapage.

entrer la description de l'image ici

C’est ce que je faisais sur mes projets Android.

Dans Android Studio, nous pouvons effectuer une opération similaire avec, Ctrl + Shift + F pour rechercher dans tout le projet (Commande + Maj + F dans MacO) et Ctrl + Maj + R pour Remplacer ((Commande + Maj + R dans MacO))

J’ai une solution très simple J’utilise IntelliJ pour le développement, donc les détails varient, mais l’idée devrait s’appliquer à tous les IDE.

Je choisis la racine de mon arbre source, cliquez avec le bouton droit et sélectionnez «remplacer». Je choisis ensuite de remplacer tous les “Log”. avec “// Log.”. Cela supprime toutes les instructions de journal. Pour les remettre plus tard, je répète le même remplacement mais cette fois, remplacez tout “// Log”. avec “Journal”.

Fonctionne très bien pour moi. N’oubliez pas de définir le remplacement comme sensible à la casse pour éviter les accidents tels que “Dialogue”. Pour plus d’assurance, vous pouvez également faire la première étape avec “Log”. comme la chaîne à rechercher.

Brillant.

Comme le suggère le commentaire de zserge ,

Timber est très sympa, mais si vous avez déjà un projet existant, vous pouvez essayer github.com/zserge/log. C’est un remplacement instantané pour android.util.Log et possède la plupart des fonctionnalités de Timber et encore plus.

sa bibliothèque de journaux fournit un simple bouton d’activation / désactivation de l’impression des journaux, comme ci-dessous.

En outre, il suffit de modifier import lignes d’ import , et rien ne doit changer pour Log.d(...); déclaration.

 if (!BuildConfig.DEBUG) Log.usePrinter(Log.ANDROID, false); // from now on Log.d etc do nothing and is likely to be optimized with JIT 

J’ai amélioré la solution ci-dessus en fournissant un support pour différents niveaux de journalisation et en modifiant automatiquement les niveaux de journalisation en fonction de l’exécution du code sur un périphérique actif ou sur l’émulateur.

 public class Log { final static int WARN = 1; final static int INFO = 2; final static int DEBUG = 3; final static int VERB = 4; static int LOG_LEVEL; static { if ("google_sdk".equals(Build.PRODUCT) || "sdk".equals(Build.PRODUCT)) { LOG_LEVEL = VERB; } else { LOG_LEVEL = INFO; } } /** *Error */ public static void e(Ssortingng tag, Ssortingng ssortingng) { android.util.Log.e(tag, ssortingng); } /** * Warn */ public static void w(Ssortingng tag, Ssortingng ssortingng) { android.util.Log.w(tag, ssortingng); } /** * Info */ public static void i(Ssortingng tag, Ssortingng ssortingng) { if(LOG_LEVEL >= INFO) { android.util.Log.i(tag, ssortingng); } } /** * Debug */ public static void d(Ssortingng tag, Ssortingng ssortingng) { if(LOG_LEVEL >= DEBUG) { android.util.Log.d(tag, ssortingng); } } /** * Verbose */ public static void v(Ssortingng tag, Ssortingng ssortingng) { if(LOG_LEVEL >= VERB) { android.util.Log.v(tag, ssortingng); } } } 

ProGuard le fera pour vous sur votre version de compilation et maintenant les bonnes nouvelles d’android.com:

http://developer.android.com/tools/help/proguard.html

L’outil ProGuard réduit, optimise et masque votre code en supprimant le code inutilisé et en renommant les classes, les champs et les méthodes avec des noms sémantiquement obscurs. Le résultat est un fichier .apk de plus petite taille, plus difficile à désosser. Étant donné que ProGuard rend votre application plus difficile à réorganiser, il est important que vous l’utilisiez lorsque votre application utilise des fonctionnalités sensibles à la sécurité, par exemple lorsque vous atsortingbuez une licence à vos applications.

ProGuard est intégré au système de génération Android, vous n’avez donc pas à l’invoquer manuellement. ProGuard s’exécute uniquement lorsque vous générez votre application en mode de publication. Vous n’avez donc pas à gérer le code obscur lorsque vous créez votre application en mode débogage. Avoir ProGuard exécuté est complètement facultatif, mais fortement recommandé.

Ce document décrit comment activer et configurer ProGuard et utiliser l’outil de suivi pour décoder les traces de stack obscurcies.

Ajouter les fichiers suivants à votre fichier proguard-rules.txt

 -assumenosideeffects class android.util.Log { public static *** d(...); public static *** w(...); public static *** v(...); public static *** i(...); } 

J’aime utiliser Log.d (TAG, une chaîne, souvent un Ssortingng.format ()).

TAG est toujours le nom de la classe

Transform Log.d (TAG, -> Logd (dans le texte de votre classe)

 private void Logd(Ssortingng str){ if (MainClass.debug) Log.d(className, str); } 

De cette façon, lorsque vous êtes prêt à créer une version, définissez MainClass.debug sur false!

Les journaux peuvent être supprimés en utilisant bash dans linux et sed:

 find . -name "*\.java" | xargs sed -ri ':a; s%Log\.[ivdwe].*\);%;%; ta; /Log\.[ivdwe]/ !b; N; ba' 

Fonctionne pour les journaux multilignes. Dans cette solution, vous pouvez être sûr que les journaux ne sont pas présents dans le code de production.

Je sais que c’est une vieille question, mais pourquoi n’avez-vous pas remplacé tous vos appels de journaux par quelque chose comme Boolean logCallWasHere = true; // — rest de votre journal ici

C’est pourquoi vous saurez quand vous voulez les remettre, et elles n’affecteront pas votre appel à une déclaration si 🙂

le plus simple

utiliser DebugLog

Tous les journaux sont désactivés par DebugLog lorsque l’application est publiée.

https://github.com/MustafaFerhan/DebugLog