Come rimuovere tutte le chiamate registrazione di debug prima di creare la versione di un'applicazione Android?

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

Domanda

Secondo Google, devo " disattivare tutte le chiamate a Registro metodi nel codice sorgente " prima di pubblicare la mia app Android su Google Play. Estratto dalla sezione 3 della pubblicazione lista di controllo :

  

Assicurati di disattivare la registrazione e disattiva l'opzione di debug prima di costruire la vostra applicazione per il rilascio. È possibile disattivare la registrazione, eliminando le chiamate a Registro metodi nei file di origine.

Il mio progetto open-source è grande ed è un dolore per farlo manualmente ogni volta che rilascio. Inoltre, la rimozione di una linea di Log è potenzialmente ingannevole, per esempio:

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

Se io commento la linea registro, la condizione si applica alla riga successiva, e le probabilità sono load () non viene chiamato. Sono tali situazioni abbastanza raro che posso decidere che non dovrebbe esistere?

Quindi, c'è un modo migliore livello di codice sorgente per farlo? O forse una sintassi ProGuard intelligente per rimuovere in modo efficiente, ma in modo sicuro tutte le linee di registro?

È stato utile?

Soluzione

trovo una soluzione di gran lunga più facile è dimenticare tutti i controlli if tutto il luogo e basta usare ProGuard per togliere eventuali chiamate di metodo Log.d() o Log.v() quando chiamiamo il nostro obiettivo release Ant.

In questo modo, abbiamo sempre informazioni di debug di essere uscita per regolare costruisce e non dobbiamo apportare modifiche al codice per la build di rilascio. ProGuard può anche fare passaggi multipli sul bytecode per rimuovere altre dichiarazioni indesiderate, blocchi vuoti e può metodi automaticamente linea brevi se del caso.

Per esempio, ecco una configurazione ProGuard molto di base per Android:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

Così si risparmia che in un file, quindi chiamare ProGuard da Ant, passando nel vostro JAR appena compilato e il JAR piattaforma Android si sta utilizzando.

Si veda anche gli esempi nel manuale ProGuard.


Aggiorna (4,5 anni più tardi): Oggi ho usato Legname per Android la registrazione.

Non solo è un po 'più bello l'implementazione predefinita Log - il tag di registro viene impostato automaticamente, ed è facile per accedere stringhe formattate ed eccezioni -., Ma è anche possibile specificare diversi comportamenti di registrazione in fase di esecuzione

In questo esempio, le dichiarazioni di registrazione sarà scritto solo per Logcat in build di debug della mia app:

Legno è impostato nel mio metodo Application onCreate():

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

Poi altrove nel mio codice posso accedere facilmente:

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

Vedere la campione legno app per un esempio più avanzato, in cui tutte le dichiarazioni di log vengono inviati a logcat durante lo sviluppo e, in produzione, senza istruzioni di debug vengono registrati, ma gli errori sono in silenzio segnalato per Crashlytics.

Altri suggerimenti

Tutte le buone risposte, ma quando ero finito con il mio sviluppo Non volevo usare sia per se le dichiarazioni di tutto tutto il registro chiamate, né ho voglia di utilizzare strumenti esterni.

Quindi la soluzione `m utilizzando è quello di sostituire la classe android.util.Log con la mia 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);
    }
}

L'unica cosa che ho dovuto fare in tutti i file di origine è stato quello di sostituire l'importazione di android.util.Log con la mia classe.

Suggerisco avere un valore booleano statico da qualche parte che indica se o meno per accedere:

class MyDebug {
  static final boolean LOG = true;
}

Quindi, ovunque si desidera accedere nel codice, basta fare questo:

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

Ora, quando si imposta MyDebug.LOG su false, il compilatore nudo fuori tutto il codice all'interno di tali controlli (dal momento che è una finale statica, sa al momento della compilazione che il codice non viene utilizzato.)

Per i progetti più grandi, si consiglia di iniziare avendo booleani in singoli file per essere in grado di abilitare facilmente o disattivare la registrazione non in base alle esigenze. Ad esempio, queste sono le varie costanti di registrazione che abbiamo nel window manager:

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;

Con codice come corrispondente:

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

soluzione Proguard di Christopher è il migliore, ma se per qualsiasi motivo non ti piace Proguard, ecco una soluzione molto low-tech:

tronchi Commento:

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

tronchi Decommenta:

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

Un vincolo è che le vostre istruzioni di registrazione non devono estendersi su più righe.

(Esegui queste righe in una shell UNIX alla radice del progetto. Se si utilizza Windows, ottenere uno strato di UNIX o utilizzare i comandi equivalente di Windows)

Vorrei aggiungere alcune precisazioni sull'utilizzo Proguard con Android Studio e Gradle, dal momento che ho avuto un sacco di problemi per rimuovere le linee di registro dal binario finale.

Al fine di rendere assumenosideeffects in Proguard funziona, v'è un prerequisito.

Nel file Gradle, è necessario specificare l'utilizzo del proguard-android-optimize.txt come file predefinito.

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'
    }
}

In realtà, nel file di default proguard-android.txt, ottimizzazione è disabilitato con le due bandiere:

-dontoptimize
-dontpreverify

Il file proguard-android-optimize.txt non aggiunge quelle linee, così ora assumenosideeffects può lavorare.

Poi, personalmente, io uso SLF4J , tanto più quando sviluppo di alcune librerie che vengono distribuiti agli altri . Il vantaggio è che di default non v'è alcuna uscita. E se l'integratore vuole alcune uscite di registro, che può usa Logback per Android e attivare i registri, in modo da tronchi può essere reindirizzato a un file oa LogCat.

Se ho davvero bisogno di spogliare i registri della biblioteca finale, ho poi aggiungo al mio file Proguard (dopo aver abilitato il file proguard-android-optimize.txt ovviamente):

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

consiglio vivamente utilizzando legname proveniente da Jake Wharton

https://github.com/JakeWharton/timber

risolve il problema con l'attivazione / disattivazione e aggiunge classe tag automagicamente

solo

public class MyApp extends Application {

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

i registri saranno utilizzati solo nella vostra di debug ver, e quindi utilizzare

Timber.d("lol");

o

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

per stampare

"La vostra classe / msg" senza specyfing il tag

Ho usato un LogUtils classe come nel esempio di applicazione Google IO. Ho modificato questo per utilizzare una specifica costante DEBUG dell'applicazione anziché BuildConfig.DEBUG perché BuildConfig .debug è inaffidabile . Poi nelle mie classi ho il seguente.

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");
  }
}

Vorrei considerare l'utilizzo di roboguice funzione di registrazione al posto del built-in Android .util.Log

La loro struttura disattiva automaticamente il debug e log dettagliati per il rilascio costruisce. Inoltre, si ottiene alcune caratteristiche nifty gratuitamente (comportamento di registrazione per esempio personalizzabile, informazioni aggiuntive su tutti i log e altri)

Utilizzando Proguard potrebbe essere piuttosto una seccatura e non vorrei passare attraverso la briga di configurazione e rendendo lavoro con l'applicazione a meno che non si dispone di una buona ragione per questo (la disattivazione registri non è un buona)

Sto postando questa soluzione che si applica specificamente per gli utenti di Studio Android. Ho anche scoperto di recente in legno e hanno importato con successo nel mio app facendo quanto segue:

Mettere l'ultima versione della libreria nel vostro build.gradle:

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

Poi in Android Studios, andare in Modifica -> Trova -> Sostituisci nel percorso ...

Digitare Log.e(TAG, o comunque aver definito i messaggi log nella casella di testo "Text to find". Poi basta sostituirlo con Timber.e(

 entrare descrizione dell'immagine qui

Fare clic su Trova e quindi sostituire tutto.

Android Studios sarà ora passare attraverso tutti i file nel progetto e sostituire tutti i registri con i Timbers.

L'unico problema che ho avuto con questo metodo è che Gradle viene in su servivano milione di messaggi di errore in seguito, perché non riesce a trovare "Legno" nelle importazioni per ciascuno dei vostri file Java. Basta cliccare sugli errori e Android Studios importerà automaticamente "Legno" nel vostro Java. Una volta che avete fatto per i file di tutti i tuoi errori, Gradle compilerà di nuovo.

È inoltre necessario mettere questo pezzo di codice nel metodo onCreate della classe Application:

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

Questo si tradurrà nella registrazione di applicazione solo quando si è in modalità di sviluppo non in produzione. Si può anche avere BuildConfig.RELEASE per l'accesso in modalità di rilascio.

Per android.util.Log fornisce un modo per abilitare / disabilitare log:

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

predefinito il metodo isLoggable (...) restituisce false, solo dopo aver SetProp nel dispositivo piace questo:

adb shell setprop log.tag.MyAppTag DEBUG

Si intende qualsiasi registro sopra il livello DEBUG può essere stampato. Riferimento DOC Android:

  

Controlla per vedere se un registro per il tag specificato è loggable al livello specificato. Il livello predefinito di qualsiasi tag è impostato   a INFO. Ciò significa che qualsiasi livello superiore e comprendente INFO sarà   registrato. Prima di effettuare qualsiasi chiamata a un metodo di registrazione si dovrebbe verificare   per vedere se il tag deve essere registrato. È possibile modificare il livello di default   impostando una proprietà di sistema: 'log.tag setprop. '   Dove il livello è o VERBOSE, DEBUG, INFO, WARN, ERROR, affermare, o   SUPPRESS. SUPPRESS si spegne tutta la registrazione per il tag. Puoi   anche creare un file local.prop che con il seguente in esso:   'Log.tag. =' E posto che in /data/local.prop.

Così abbiamo potuto usare il login personalizzato util:

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);
    }
}

Se è possibile eseguire una sostituzione globale (una volta), e dopo che conserva una certa convenzione di codifica, è possibile seguire il modello usato spesso in Android quadro .

Invece di scrivere

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

avere come

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

Ora Proguard può rimuovere lo StringBuilder e tutte le stringhe ei metodi che utilizza sulla strada, dalla versione ottimizzata DEX. Utilizzare proguard-android-optimize.txt e non c'è bisogno di preoccuparsi di android.util.Log nella tua proguard-rules.pro:

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

Con Studio Android plug Gradle, BuildConfig.DEBUG è abbastanza affidabile, quindi non è necessario costanti in più per controllare lo stripping.

Ho una soluzione molto semplice. Io uso IntelliJ per lo sviluppo, in modo che i dettagli variano, ma l'idea dovrebbe applicarsi in tutti IDE.

I pick alla radice del mio albero dei sorgenti, fare clic destro e selezionare per fare "sostituire". Ho quindi scelto di sostituire tutti "Log." con "// Log.". Questo rimuove tutte le dichiarazioni di registro. Per mettere di nuovo in seguito ripeto la stessa sostituire, ma questa volta come sostituire tutti "// Log." con "Log.".

funziona solo grande per me. Basta ricordarsi di impostare la sostituzione di maiuscole e minuscole per evitare incidenti come il "dialogo".. Per la garanzia aggiuntiva, è possibile anche fare il primo passo con il "Log". come la stringa da cercare.

brillante.

Il commento di zserge suggerito,

  

Il legno è molto bello, ma se si dispone già di un progetto esistente - si può tentare github.com/zserge/log. Si tratta di un rimpiazzo per android.util.Log e ha la maggior parte delle caratteristiche che il legname ha e anche di più.

sua biblioteca registro fornisce semplice attivare / disattivare l'interruttore stampa log come di seguito.

Inoltre, solo richiede di cambiare le linee import, e non ha bisogno di cambiare per la dichiarazione 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

Aggiungi al seguente Proguard-rules.txt file

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

entrare descrizione dell'immagine qui

Questo è quello che ho usato per fare i miei progetti android ..

In Android Studio possiamo fare un'operazione simile da, Ctrl + Shift + F per trovare da tutto il progetto (Command + Shift + F in MacOS) e Ctrl + Maiusc + R per sostituire ((Command + Shift + R in MacOS) )

ho migliorato sulla soluzione sopra fornendo un supporto per i diversi livelli di registro e cambiando i livelli di log automaticamente a seconda se il codice è eseguito su un dispositivo vivo o nell'emulatore.

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 lo farà per voi sul vostro build di rilascio e ora le buone notizie da android.com:

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

Lo strumento ProGuard si restringe, ottimizza e offusca il codice rimuovendo il codice inutilizzato e rinominare le classi, i campi ei metodi con i nomi semanticamente oscuri. Il risultato è un file .apk di dimensioni più piccolo che è più difficile da decodificare. Perché ProGuard rende l'applicazione più difficile da decodificare, è importante che lo si utilizza quando l'applicazione utilizza funzioni che sono sensibili alla sicurezza come quando si richiede la licenza delle applicazioni.

ProGuard è integrato nel sistema di compilazione di Android, in modo da non dover richiamare manualmente. ProGuard viene eseguito solo quando si genera l'applicazione in modalità di rilascio, in modo da non avere a che fare con il codice offuscato quando si genera l'applicazione in modalità di debug. Avere corsa ProGuard è completamente facoltativo, ma altamente raccomandato.

Questo documento descrive come abilitare e configurare ProGuard così come utilizzare lo strumento ritracciamento di decodificare tracce dello stack offuscati

Mi piace usare Log.d (TAG, una stringa, spesso uno String.Format ()).

TAG è sempre il nome della classe

Trasforma Log.d (TAG, -> LoGD (nel testo della tua classe

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

In questo modo, quando si è pronti a fare una versione di rilascio, impostare MainClass.debug false!

I registri possono essere rimossi con bash in Linux e sed:

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

Opere per i registri multilinea. In questa soluzione si può essere sicuri, che i registri non sono presenti nel codice di produzione.

So che questa è una vecchia questione, ma il motivo per cui non ha sostituito tutto il registro chiamate con qualcosa di simile Booleano logCallWasHere = true; // --- resto del registro qui

Questo il motivo per cui si sa quando si vuole mettere di nuovo, e non influenzerà la vostra chiamata se dichiarazione:)

Perché non fare

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

? Non ci sono librerie aggiuntive necessarie, senza regole Proguard che tendono a rovinare il progetto e compilatore Java sarà solo lasciare fuori bytecode per questa chiamata quando si effettua build di rilascio.

il modo più semplice;

uso DebugLog

Tutti i registri sono disabilitate per DebugLog quando l'applicazione viene rilasciato.

https://github.com/MustafaFerhan/DebugLog

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top