Comment faire pour supprimer tous la journalisation du débogage des appels avant la construction de la version d'une application Android?

StackOverflow https://stackoverflow.com/questions/2446248

Question

Selon Google, je dois "désactiver tous les appels à des méthodes de Log dans le code source"avant de publier mon application Android sur Google Play.Extrait de l'article 3 de la publication de la liste de contrôle:

Assurez-vous de désactiver la journalisation et de désactiver l'option de débogage avant de vous construire votre demande de mise en liberté.Vous pouvez désactiver la journalisation en supprimant les appels aux méthodes du Journal dans vos fichiers source.

Mon projet open-source est grande et il est une douleur à le faire manuellement à chaque fois que je la libération.En outre, la suppression d'une ligne de Journal est potentiellement difficile, par exemple:

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

Si je commente la ligne du Journal, alors la condition s'applique à la ligne suivante, et les chances sont load() n'est pas appelée.Sont de telles situations assez rare pour que je puisse décider qu'il ne devrait pas exister?

Alors, est-il un meilleur niveau de code source façon de le faire?Ou peut-être quelques petits malins ProGuard syntaxe de manière efficace, mais en toute sécurité supprimer toutes les lignes du Journal?

Était-ce utile?

La solution

Je trouve une solution beaucoup plus facile est d'oublier tous les contrôles de if dans tous les sens et il suffit d'utiliser ProGuard enlever toute appels de méthode Log.d() ou Log.v() lorsque nous appelons notre cible Ant release.

De cette façon, nous avons toujours les informations de débogage étant sortie pour régulière construit et ne doivent pas apporter des modifications de code pour la mise construit. ProGuard peut aussi faire plusieurs passes sur le bytecode pour éliminer d'autres déclarations indésirables, des blocs vides et peut automatiquement les méthodes en ligne de courts 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(...);
}

Alors, vous économiseriez que dans un fichier, puis appelez ProGuard de Ant, en passant dans votre juste compilé JAR et la plate-forme Android JAR que vous utilisez.

Voir aussi les exemples dans le manuel ProGuard.


Mise à jour (4,5 ans plus tard): Aujourd'hui je rel="noreferrer"> du bois pour Android journalisation.

Non seulement il est un peu mieux que la mise en œuvre de Log par défaut - la balise de journal est automatiquement, et il est facile de se connecter chaînes formatées et exceptions -. Mais vous pouvez également spécifier différents comportements d'exploitation lors de l'exécution

Dans cet exemple, les déclarations d'exploitation forestière ne sera écrit à LogCat dans debug de mon application:

Le bois est mis en place dans ma méthode de Application onCreate():

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

Alors nulle part ailleurs dans mon code, je peux me connecter facilement:

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

Voir

Autres conseils

Toutes les bonnes réponses, mais quand je suis fini avec mon développement, je veux didnt soit utiliser si des déclarations autour de tous les Consigner les appels, pas plus que je veux utiliser des outils externes.

Donc, la solution I `m en utilisant est de remplacer la classe android.util.Log avec ma propre classe Log:

public class Log {
    static final boolean LOG = BuildConfig.DEBUG;

    public static void i(String tag, String string) {
        if (LOG) android.util.Log.i(tag, string);
    }
    public static void e(String tag, String string) {
        if (LOG) android.util.Log.e(tag, string);
    }
    public static void d(String tag, String string) {
        if (LOG) android.util.Log.d(tag, string);
    }
    public static void v(String tag, String string) {
        if (LOG) android.util.Log.v(tag, string);
    }
    public static void w(String tag, String string) {
        if (LOG) android.util.Log.w(tag, string);
    }
}

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

Je suggère d'avoir une valeur booléenne indiquant un endroit statique pour vous connecter si oui ou non:

class MyDebug {
  static final boolean LOG = true;
}

Alors où vous voulez vous connecter dans votre code, faites ceci:

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

Maintenant, lorsque vous définissez MyDebug.LOG false, le compilateur dépouilleront tout le code à l'intérieur de ces contrôles (car il est une finale statique, il sait au moment de la compilation que le code n'est pas utilisé.)

Pour les grands projets, vous voudrez peut-être commencer à avoir booléens dans des fichiers individuels pour pouvoir facilement activer ou désactiver la journalisation au besoin il. Par exemple, ce sont les différentes constantes d'exploitation que nous avons dans le gestionnaire de fenêtres:

static final String 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 à:

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

La solution de Christopher Proguard est le meilleur, mais si pour une raison quelconque, vous ne l'aimez pas Proguard, voici une solution très low-tech:

journaux de commentaires:

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

journaux Uncomment:

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

Une contrainte est que vos instructions d'exploitation ne doivent pas s'étendre sur plusieurs lignes.

(Execute ces lignes dans un shell UNIX à la racine de votre projet. Si vous utilisez Windows, obtenir une couche UNIX ou utiliser les commandes équivalentes Windows)

Je voudrais ajouter quelques précisions sur l'utilisation Proguard avec Android Studio gradle, depuis que j'ai eu beaucoup de problèmes pour supprimer des lignes de journaux à partir du binaire final.

Afin de assumenosideeffects dans les travaux Proguard, il y a une condition sine qua non.

Dans votre fichier gradle, vous devez spécifier l'utilisation du 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 fichier proguard-android.txt par défaut, l'optimisation est désactivée avec les deux drapeaux:

-dontoptimize
-dontpreverify

Le fichier proguard-android-optimize.txt ne pas ajouter ces lignes, maintenant assumenosideeffects peut travailler.

Alors, personellement, j'utilise SLF4J , d'autant plus que je développe des bibliothèques qui sont distribués à d'autres . L'avantage est que par défaut il n'y a pas de sortie. Et si l'intégrateur veut des sorties du journal, il utilise peut Logback pour Android et activer les journaux, donc les journaux peuvent être redirigés vers un fichier ou LogCat.

Si je vraiment besoin de dépouiller les journaux de la bibliothèque finale, je puis ajouter à mon dossier Proguard (après avoir activé le fichier proguard-android-optimize.txt bien sûr):

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

Je vous suggère fortement l'utilisation du bois de Jake Wharton

https://github.com/JakeWharton/timber

il résout votre problème avec l'activation / désactivation plus ajoute la classe tag automagiquement

juste

public class MyApp extends Application {

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

journaux ne seront utilisées que dans votre débogage ver, puis utilisez

Timber.d("lol");

ou

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

pour imprimer

"Votre classe / msg" sans specyfing la balise

Je l'ai utilisé un la classe de LogUtils comme dans l'exemple d'application Google IO. J'ai modifié cette option pour utiliser une constante DEBUG spécifique à l'application au lieu de BuildConfig.DEBUG parce que buildconfig .debug est peu fiable . Puis, dans mes classes, je donne les résultats suivants.

import static my.app.util.LogUtils.makeLogTag;
import static my.app.util.LogUtils.LOGV;

public class MyActivity extends FragmentActivity {
  private static final String TAG = makeLogTag(MyActivity.class);

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    LOGV(TAG, "my message");
  }
}

Je souhaite publier cette solution qui applique spécifiquement pour les utilisateurs Android Studio. J'ai aussi récemment découvert du bois et ont importé avec succès dans mon application en procédant comme suit:

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

compile 'com.jakewharton.timber:timber:4.1.1'

Puis dans Android Studios, allez dans Edition -> Rechercher -> Remplacer dans le chemin ...

Tapez Log.e(TAG, ou cependant vous avez défini vos messages Connectez-vous à la zone de texte "Text to find". Ensuite, vous remplacez juste avec Timber.e(

 ici

Cliquez sur Rechercher puis remplacer tous.

Android Studios va maintenant à travers tous vos fichiers dans votre projet et remplacer tous les journaux avec Timbers.

Le seul problème que j'avais avec cette méthode est que gradle ne vient les messages d'erreur avecun millions après parce qu'il ne peut pas trouver « bois » dans les importations pour chacun de vos fichiers java. Il suffit de cliquer sur les erreurs et Android Studios importera automatiquement « bois » dans votre java. Une fois que vous l'avez fait pour tous vos fichiers d'erreurs, gradle compilera à nouveau.

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

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

Cela se traduira par l'enregistrement de l'application que lorsque vous êtes en mode de développement non dans la production. Vous pouvez également vous connecter BuildConfig.RELEASE pour le mode de libération.

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

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

Par défaut la méthode isLoggable (...) retourne false, seulement après que vous setprop dans l'appareil aime ceci:

adb shell setprop log.tag.MyAppTag DEBUG

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

  

Vérifie si oui ou non un journal pour la balise spécifiée est loggable au niveau spécifié. Le niveau par défaut de toute balise est définie   à INFO. Cela signifie que tout niveau au-dessus et dont INFO sera   connecté. Avant de faire des appels à une méthode de journalisation vous devriez vérifier   pour voir si votre balise doit être connecté. Vous pouvez modifier le niveau par défaut   en définissant une propriété du système: « setprop log.tag. '   Quand le niveau est soit VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, ou   RÉPRIMER. SUPPRESS s'éteint toute exploitation forestière pour votre tag. Vous pouvez   aussi créer un fichier qui local.prop avec ce qui suit dans le:   'Log.tag. =' Et lieu que dans /data/local.prop.

Nous pourrions utiliser util log personnalisé:

public final class Dlog 
{
    public static void v(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.VERBOSE))
            Log.v(tag, msg);
    }

    public static void d(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.DEBUG))
            Log.d(tag, msg);
    }

    public static void i(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.INFO))
            Log.i(tag, msg);
    }

    public static void w(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.WARN))
            Log.w(tag, msg);
    }

    public static void e(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.ERROR))
            Log.e(tag, msg);
    }
}

Si vous pouvez exécuter un remplacement global (une fois), et après une chasse gardée convention de codage, vous pouvez suivre le modèle souvent utilisé dans Android cadre .

Au lieu d'écrire

Log.d(TAG, string1 + string2 + arg3.toString());

ont comme

if (BuildConfig.DEBUG) Log.d(TAG, string1 + String.format("%.2f", arg2) + arg3.toString());

proguard peut supprimer le StringBuilder et toutes les chaînes et les méthodes qu'il utilise sur le chemin, de sortie optimisé DEX. Utilisez proguard-android-optimize.txt et vous n'avez pas à vous soucier de android.util.Log dans votre proguard-rules.pro:

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

Avec le plugin Android Studio est gradle, BuildConfig.DEBUG est tout à fait fiable, de sorte que vous n'avez pas besoin des constantes supplémentaires pour contrôler le décapage.

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

IDE.

Je prends à la racine de mon arbre source, droit de la souris et sélectionnez pour faire « remplacer ». Je choisis alors de remplacer tous les « Log ». avec "// Log.". Cela supprime toutes les instructions du journal. Pour les remettre plus tard, je répète la même remplacer, mais cette fois comme remplacer tous les « // Log. » avec "Log.".

Fonctionne très bien pour moi. Rappelez-vous de régler le remplacer comme sensible à la casse pour éviter les accidents tels que « Dialog. ». Pour une assurance supplémentaire, vous pouvez également faire la première étape avec « Log. » comme la chaîne de recherche.

Brillant.

commentaire de zserge suggéré,

  

Le bois est très agréable, mais si vous avez déjà un projet existant - vous pouvez essayer github.com/zserge/log. Il est un remplacement de halte-accueil pour android.util.Log et a la plupart des caractéristiques que le bois a et plus encore.

sa bibliothèque journal fournit simplement activer / désactiver le commutateur d'impression du journal comme ci-dessous.

En outre, que afin de changer de ligne de import, et rien doit changer pour instruction Log.d(...);.

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

Ajoutez suivante à votre proguard-rules.txt fichier

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

est ce que je faisais sur mes projets Android ..

Dans Android Studio Nous pouvons faire opération similaire par Ctrl + Maj + F pour trouver du projet entier (Commande + Maj + F dans MacOs) et Ctrl + Maj + R pour remplacer ((Commande + Maj + R dans MacOs) )

I ai amélioré sur la solution ci-dessus en fournissant un support pour les différents niveaux de journal et en changeant les niveaux de journal automatiquement en fonction de si le code est exécuté sur un dispositif en temps réel 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(String tag, String string)
{
        android.util.Log.e(tag, string);
}

/**
 * Warn
 */
public static void w(String tag, String string)
{
        android.util.Log.w(tag, string);
}

/**
 * Info
 */
public static void i(String tag, String string)
{
    if(LOG_LEVEL >= INFO)
    {
        android.util.Log.i(tag, string);
    }
}

/**
 * Debug
 */
public static void d(String tag, String string)
{
    if(LOG_LEVEL >= DEBUG)
    {
        android.util.Log.d(tag, string);
    }
}

/**
 * Verbose
 */
public static void v(String tag, String string)
{
    if(LOG_LEVEL >= VERB)
    {
        android.util.Log.v(tag, string);
    }
}


}

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

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

L'outil ProGuard se rétrécit, optimise et obscurcit votre code en supprimant le code utilisé et de renommer les classes, les champs et les méthodes avec des noms sémantiquement obscurs. Le résultat est un fichier .apk plus petite taille qui est plus difficile à désosser. Parce que ProGuard rend votre application plus difficile à désosser, il est important que vous utilisez lorsque votre application utilise des fonctionnalités qui sont sensibles à la sécurité comme lorsque vous proposez une licence pour vos applications.

ProGuard est intégré dans le système de construction Android, de sorte que vous ne devez pas l'invoquer manuellement. ProGuard ne fonctionne que lorsque vous créez votre application en mode release, donc vous ne devez pas traiter avec le code lorsque vous créez Obfuscated votre application en mode débogage. Après avoir tenu ProGuard est totalement facultatif, mais fortement recommandé.

Ce document décrit comment activer et configurer ProGuard ainsi que l'utilisation de l'outil de retour pour décoder les traces de pile brouillées

J'aime utiliser Log.d (TAG, une chaîne de caractères, souvent String.format ()).

est toujours le nom de la classe

Transformer Log.d (TAG, -> LOGD (dans le texte de votre classe

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

De cette façon, lorsque vous êtes prêt à faire une version, mettre MainClass.debug false

Les journaux peuvent être retirés à l'aide bash sous Linux et DÉS:

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

Travaux 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 ne pas vous remplacer tous vos appels journal avec quelque chose comme Boolean logCallWasHere = true; // --- reste de votre journal ici

Ce pourquoi vous saurez quand vous voulez les remettre, et ils ne seront pas affecter votre appel si la déclaration:)

Pourquoi ne pas simplement faire

if(BuildConfig.DEBUG)
  Log.d("tag","msg");

? Aucune bibliothèque supplémentaire nécessaire, pas de règles ProGuard qui tendent à bousiller le projet et compilateur java vont tout simplement laisser de bytecode pour pour cet appel lorsque vous faites construire la libération.

la façon la plus simple;

utilisation DebugLog

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

https://github.com/MustafaFerhan/DebugLog

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top