Wie entfernen Sie alle Debug -Protokollierungsanrufe, bevor Sie die Release -Version einer Android -App erstellen?

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

Frage

Laut Google muss ich "Deaktivieren Sie alle Aufrufe zum Protokollieren von Methoden im Quellcode"Vor der Veröffentlichung meiner Android -App an Google Play. Extrahieren Sie aus Abschnitt 3 der Publikations -Checkliste:

Stellen Sie sicher, dass Sie die Protokollierung deaktivieren und die Debugging -Option deaktivieren, bevor Sie Ihre Bewerbung zur Veröffentlichung erstellen. Sie können die Protokollierung deaktivieren, indem Sie Aufrufe zu Protokollmethoden in Ihren Quelldateien entfernen.

Mein Open-Source-Projekt ist groß und es ist ein Schmerz, es jedes Mal, wenn ich freie freie, manuell zu tun. Darüber hinaus ist das Entfernen einer Protokolllinie beispielsweise möglicherweise schwierig:

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

Wenn ich die Protokollzeile kommentiere, gilt die Bedingung für die nächste Zeile, und die Chancen werden geladen () nicht aufgerufen. Sind solche Situationen selten genug, dass ich entscheiden kann, dass es nicht existieren sollte?

Gibt es also eine bessere Möglichkeit, Code-Code-Ebene zu tun? Oder vielleicht eine clevere Proguard -Syntax, um alle Protokollleitungen effizient zu entfernen, aber sicher zu entfernen?

War es hilfreich?

Lösung

Ich finde eine weitaus einfachere Lösung, alle zu vergessen if Überprüft überall und verwenden Sie einfach nur Proguard jeden ausziehen Log.d() oder Log.v() Methodenaufrufe, wenn wir unsere Ameise anrufen release Ziel.

Auf diese Weise haben wir immer die Debug -Informationen für reguläre Builds und müssen keine Codeänderungen für Release -Builds vornehmen. Proguard kann auch mehrere Durchgänge über dem Bytecode durchführen, um andere unerwünschte Anweisungen, leere Blöcke zu entfernen und gegebenenfalls automatisch kurze Methoden inline.

Hier finden Sie beispielsweise eine sehr einfache Proguard -Konfiguration für Android:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

Sie speichern das in einer Datei und rufen dann Proguard von ANT an und geben in Ihrem gerade kompilierten Glas und dem von Ihnen verwendeten Android-Plattform-JAR weiter.

Siehe auch die Beispiele im Proguard -Handbuch.


Update (4,5 Jahre später): Heutzutage habe ich verwendet Holz Für Android -Protokollierung.

Es ist nicht nur etwas schöner als der Standard Log Implementierung - Das Protokoll -Tag wird automatisch festgelegt und es ist einfach, formatierte Zeichenfolgen und Ausnahmen zu protokollieren. Sie können jedoch auch zur Laufzeit verschiedene Protokollierungsverhalten angeben.

In diesem Beispiel werden Protokollierungsanweisungen nur in Debug -Builds meiner App an Logcat geschrieben:

Holz ist in meinem eingerichtet Application onCreate() Methode:

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

Dann kann ich irgendwo anders in meinem Code problemlos protokollieren:

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

Siehe das Holz Beispiel App Für ein fortgeschritteneres Beispiel, bei dem alle Protokollanweisungen während der Entwicklung an LogCat gesendet werden und in der Produktion keine Debug -Anweisungen protokolliert werden, jedoch Fehler stillschweigend an Crashlytics gemeldet werden.

Andere Tipps

Alle guten Antworten, aber als ich mit meiner Entwicklung beendet war, wollte ich nicht verwenden, wenn Anweisungen über alle Protokollanrufe und ich wollte auch externe Tools verwenden.

Die Lösung, die ich verwende, besteht darin, die Android.util.log -Klasse durch meine eigene Protokollklasse zu ersetzen:

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

Das einzige, was ich in allen Quelldateien tun musste, war, den Import von Android.util.log durch meine eigene Klasse zu ersetzen.

Ich schlage vor, einen statischen Booleschen irgendwo zu haben, der angibt, ob ich mich log. angeben soll:

class MyDebug {
  static final boolean LOG = true;
}

Dann, wo immer Sie sich in Ihrem Code anmelden möchten, tun Sie dies einfach:

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

Wenn Sie nun mydebug.log auf false festlegen, streift der Compiler alle Code in solchen Schecks aus (da es sich um ein statisches Finale handelt, weiß er, dass der Code nicht verwendet wird.)

Für größere Projekte möchten Sie möglicherweise mit Booleschen in einzelnen Dateien beginnen, um die Protokollierung bei Bedarf leicht zu aktivieren oder zu deaktivieren. Dies sind beispielsweise die verschiedenen Protokollierungskonstanten, die wir im Fenstermanager haben:

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;

Mit entsprechendem Code wie:

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

Die Proguard-Lösung von Christopher ist die beste, aber wenn Sie Proguard aus irgendeinem Grund nicht mögen, finden Sie hier eine sehr Low-Tech-Lösung:

Kommentarprotokolle:

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

Kontrollprotokolle:

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

Eine Einschränkung besteht darin, dass Ihre Protokollierungsanweisungen nicht über mehrere Zeilen erstrecken dürfen.

(Führen Sie diese Zeilen in einer UNIX -Shell am Root Ihres Projekts aus. Wenn Sie Windows verwenden, erhalten Sie eine Unix -Ebene oder verwenden Sie äquivalente Windows -Befehle.)

Ich möchte einige Präzisionen hinsichtlich der Verwendung von Proguard mit Android Studio und Gradle hinzufügen, da ich viele Probleme hatte, Protokolllinien aus der endgültigen Binärdatei zu entfernen.

Damit assumenosideeffects In Proguard Works gibt es eine Voraussetzung.

In Ihrer Gradle -Datei müssen Sie die Verwendung der Verwendung angeben proguard-android-optimize.txt als Standarddatei.

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

Eigentlich in der Standardeinstellung proguard-android.txt Datei, Optimierung wird mit den beiden Flags deaktiviert:

-dontoptimize
-dontpreverify

Das proguard-android-optimize.txt Die Datei fügt diese Zeilen nicht hinzu, also jetzt jetzt assumenosideeffects kann arbeiten.

Dann benutze ich persönlich nicht Slf4j, Umso mehr, wenn ich einige Bibliotheken entwickle, die an andere verteilt sind. Der Vorteil ist, dass standardmäßig keine Ausgabe vorliegt. Und wenn der Integrator einige Protokollausgaben wünscht, kann er einen Logback für Android verwenden und die Protokolle aktivieren, sodass Protokolle in eine Datei oder an Logcat umgeleitet werden können.

Wenn ich die Protokolle wirklich aus der endgültigen Bibliothek ausziehen muss, füge ich dann meine Proguard -Datei hinzu (nachdem ich die aktiviert habe proguard-android-optimize.txt Datei natürlich):

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

Ich empfehle dringend, Holz von Jake Wharton zu verwenden

https://github.com/jakewharton/timber

Es löst Ihr Problem mit Aktivieren/Deaktivieren Plus Fühe Tagsklassen automatisch

nur

public class MyApp extends Application {

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

Protokolle werden nur in Ihrem Debuggen verwendet und dann verwenden

Timber.d("lol");

oder

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

zu drucken

"Ihre Klasse / MSG", ohne das Tag zu spekulieren

Ich habe a verwendet Logutils Klasse wie in der Google IO -Beispielanwendung. Ich habe dies so geändert, dass eine anwendungsspezifische Debug -Konstante anstelle von BuildConfig.debug verwendet wird, weil BuildConfig.Debug ist unzuverlässig. Dann habe ich in meinen Klassen Folgendes.

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

Ich würde in Betracht ziehen, Roboguice zu verwenden Protokollierungseinrichtung anstelle des eingebauten Android.util.logs

Ihre Einrichtung deaktiviert automatisch Debug- und ausführliche Protokolle für Release -Builds. Außerdem erhalten Sie einige raffinierte Funktionen kostenlos (z. B. anpassbares Protokollierungsverhalten, zusätzliche Daten für jedes Protokoll und mehr).

Die Verwendung von Proguard könnte ein ziemlicher Aufwand sein, und ich würde mich nicht die Mühe machen, es zu konfigurieren und zu machen Arbeit Mit Ihrer Bewerbung, es sei denn, Sie haben einen guten Grund dafür (Deaktivieren von Protokollen ist nicht gut)

Ich veröffentliche diese Lösung, die speziell für Android Studio -Benutzer gilt. Ich habe auch kürzlich Holz entdeckt und es erfolgreich in meine App importiert, indem ich Folgendes mache:

Geben Sie die neueste Version der Bibliothek in Ihren Build ein. Gradle:

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

Dann in Android Studios, wechseln Sie zu Bearbeiten -> Finden -> Ersetzen Sie im Pfad ...

Eintippen Log.e(TAG, oder wie auch immer Sie Ihre Protokollnachrichten in die definiert haben "Text to find" Textfeld. Dann ersetzen Sie es einfach durch Timber.e(

enter image description here

Klicken Sie auf Suchen und ersetzen Sie dann alle.

Android Studios wird nun alle Ihre Dateien in Ihrem Projekt durchlaufen und alle Protokolle durch Hölzer ersetzen.

Das einzige Problem, das ich mit dieser Methode hatte, ist, dass Gradle anschließend eine Million Fehlermeldungen erstellt, da es in den Importen für jede Ihrer Java -Dateien nicht "Holz" finden kann. Klicken Sie einfach auf die Fehler und Android Studios importieren automatisch "Holz" in Ihre Java. Sobald Sie es für alle Ihre Fehlerdateien getan haben, wird Gradle erneut kompilieren.

Sie müssen diesen Code auch in Ihr Stück einfügen onCreate Methode Ihrer Application Klasse:

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

Dies führt dazu, dass die App -Protokollierung nur dann, wenn Sie im Entwicklungsmodus sind, nicht in der Produktion sind. Sie können auch haben BuildConfig.RELEASE Für die Protokollierung im Release -Modus.

Per android.util.log bietet eine Möglichkeit, Protokoll zu aktivieren/zu deaktivieren:

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

Standard die Methode isLoggable (...) gibt false zurück, erst, nachdem Sie in Geräte eingestellt haben, gefällt Folgendes:

adb shell setprop log.tag.MyAppTag DEBUG

Es bedeutet, dass jedes Protokoll über Debug -Level ausgedruckt werden kann. Referenz Android Doc:

Überprüfen Sie, ob ein Protokoll für das angegebene Tag auf der angegebenen Ebene protokollierbar ist oder nicht. Die Standardstufe eines Tags ist auf Info gesetzt. Dies bedeutet, dass jede Ebene oben und einschließlich Informationen angemeldet wird. Bevor Sie Anrufe bei einer Protokollierungsmethode tätigen, sollten Sie prüfen, ob Ihr Tag protokolliert werden soll. Sie können die Standardebene ändern, indem Sie eine Systemeigenschaft einstellen: 'setProp -log.tag. 'Wo Ebene entweder ausführlich, Debugg, Info, Warn, Fehler, Assert oder Unterdrückung ist. Suppress schaltet die gesamte Protokollierung für Ihr Tag aus. Sie können auch eine lokale.Prop -Datei erstellen, die mit folgendem Folgendes darin ist: 'log.tag. =' Und platzieren in /data/local.prop.

So konnten wir benutzerdefinierte Protokoll -Utile verwenden:

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

Wenn Sie (einmal) einen globalen Ersatz ausführen können und danach eine Codierungskonvention erhalten, können Sie das in Android häufig verwendete Muster folgen Rahmen.

Anstatt zu schreiben

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

habe es als

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

Jetzt kann Proguard den StringBuilder und alle Zeichenfolgen und Methoden, die er unterwegs verwendet, aus optimiertem Release Dex entfernen. Verwenden proguard-android-optimize.txt Und Sie müssen sich keine Sorgen machen Android.util.log in deiner proguard-rules.pro:

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

Mit Android Studio Gradle Plugin, BuildConfig.DEBUGGEN ist ziemlich zuverlässig, sodass Sie keine zusätzlichen Konstanten benötigen, um das Stripping zu kontrollieren.

Ich habe eine sehr einfache Lösung. Ich benutze Intellij für die Entwicklung, daher variieren die Details, aber die Idee sollte in allen IDEs gelten.

Ich wähle die Wurzel meines Quellbaums, klicke mit der rechten Maustaste und wähle "Ersatz" aus. Ich entscheide dann alle "Protokoll". mit "// log.". Dadurch werden alle Protokollanweisungen entfernt. Um sie später zurückzusetzen, wiederhole ich das gleiche Ersatz, aber diesmal ersetzen Sie alle "// log". mit "log.".

Funktioniert einfach gut für mich. Denken Sie nur daran, den Ersatz als fallempfindlich einzustellen, um Unfälle wie "Dialog" zu vermeiden. Für zusätzliche Sicherheit können Sie auch den ersten Schritt mit "Protokoll" machen. als String zu suchen.

Brillant.

Wie Zserge Kommentar empfohlen,

Holz ist sehr nett, aber wenn Sie bereits ein vorhandenes Projekt haben, können Sie github.com/zserge/log probieren. Es ist ein Drop-In-Ersatz für Android.util.log und verfügt über die meisten Funktionen, die Holz hat und noch mehr.

seine Protokollbibliothek Bietet einfachen Aktivieren/Deaktivieren von Protokolldruckschalter wie unten.

Darüber hinaus, es nur muss sich ändern import Zeilen und nichts muss sich ändern für Log.d(...); Aussage.

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

Fügen Sie Ihrem Folgenden hinzu proguard-rules.txt Datei

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

enter image description here

Das habe ich früher bei meinen Android -Projekten gemacht.

In Android Studio können wir einen ähnlichen Betrieb durchführen, Strg+Shift+F, um aus dem gesamten Projekt (Befehl+Shift+F in MacOS) und Strg+Shift+R zu ersetzen ((Befehl+Shift+R in macOS))

Ich habe die obige Lösung verbessert, indem ich Unterstützung für unterschiedliche Protokollpegel und die automatische Änderung der Protokollebenen, je nachdem, ob der Code auf einem Live -Gerät oder auf dem Emulator ausgeführt wird, geändert hat.

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 wird es für Sie in Ihrer Veröffentlichung erstellen und jetzt die guten Nachrichten von Android.com:

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

Das Proguard -Tool schrumpft, optimiert und verschleiert Ihren Code, indem sie nicht verwendete Code entfernen und Klassen, Felder und Methoden mit semantisch dunklen Namen umbenennen. Das Ergebnis ist eine kleinere .APK -Datei, die der Ingenieur schwieriger ist. Da Proguard Ihre Anwendung schwieriger macht, den Ingenieur umzukehren, ist es wichtig, dass Sie sie verwenden, wenn Ihre Anwendung Funktionen verwendet, die für die Sicherheit empfindlich sind, wie bei der Lizenzierung Ihrer Anwendungen.

Proguard ist in das Android -Build -System integriert, sodass Sie es nicht manuell aufrufen müssen. Proguard wird nur ausgeführt, wenn Sie Ihre Anwendung im Release -Modus erstellen. Sie müssen sich daher nicht mit verschleierten Code befassen, wenn Sie Ihre Anwendung im Debug -Modus erstellen. Der Proguard -Lauf ist völlig optional, aber sehr empfohlen.

In diesem Dokument wird beschrieben

Ich benutze gerne log.d (Tag, eine Zeichenfolge, oft eine String.Format ()).

Tag ist immer der Klassenname

Transformieren log.d (Tag, -> logd (im Text Ihrer Klasse

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

Wenn Sie bereit sind, eine Release -Version zu erstellen, setzen Sie MainClass.debug auf false!

Protokolle können mit Bash unter Linux und SED entfernt werden:

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

Funktioniert für Multiline -Protokolle. In dieser Lösung können Sie sicher sein, dass Protokolle im Produktionscode nicht vorhanden sind.

Ich weiß, dass dies eine alte Frage ist, aber warum haben Sie nicht alle Ihre Protokollanrufe durch so etwas wie boolean logcallWashere = true ersetzt? // --- Rest Ihres Protokolls hier

Aus diesem Grund wissen Sie, wann Sie sie zurücklegen möchten, und sie werden sich nicht auf Ihre Anweisung auswirken :)

Warum nicht einfach tun

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

? Keine zusätzlichen Bibliotheken benötigt, keine Proguard -Regeln, die dazu neigen, das Projekt zu vermasseln, und Java Compiler wird Bytecode für diesen Anruf auslassen, wenn Sie die Release -Build erstellen.

der einfachste Weg;

verwenden DebugLog

Alle Protokolle werden von Debuglog deaktiviert, wenn die App veröffentlicht wird.

https://github.com/mustafafaferhan/debuglog

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top