Cómo eliminar todo el registro de depuración de las llamadas antes de la construcción de la versión de lanzamiento de una aplicación para Android?

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

Pregunta

Según Google, debo "desactivar las llamadas a métodos de Registro en el código fuente"antes de publicar mi aplicación de Android en Google Play.Extracto del artículo 3 de la publicación de la lista de verificación:

Asegúrese de desactivar el registro y deshabilitar la opción de depuración antes de crear su aplicación para la liberación.Usted puede desactivar el registro mediante la eliminación de las llamadas a los métodos de Registro en los archivos de origen.

Mi proyecto de código abierto es grande y es un dolor que hacerlo manualmente cada vez que me suelte.Además, la eliminación de una línea de Registro es potencialmente difícil, por ejemplo:

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

Si un comentario de la línea de Registro, entonces la condición se aplica a la línea siguiente, y las posibilidades son de carga() no se llama.Son situaciones bastante raro que yo pueda decidir no debería existir?

Así que, ¿hay una mejor fuente de nivel de código para hacer eso?O tal vez algún inteligente ProGuard sintaxis de manera eficiente, pero de manera segura de eliminar todas las líneas del Registro?

¿Fue útil?

Solución

Me parece una solución mucho más fácil es olvidar todos los controles if por todo el lugar y sólo usar ProGuard que se deben eliminar cualquier Log.d() o Log.v() método llamadas cuando llamamos nuestro objetivo release Ant.

De esa manera, siempre tenemos la información de depuración que se emite por regulares construye y no tenemos que hacer ningún cambio de código para las versiones de lanzamiento. ProGuard también puede hacer múltiples pasadas sobre el código de bytes para eliminar otros estados no deseados, bloques vacíos y puede métodos automáticamente inline cortos en su caso.

Por ejemplo, he aquí una configuración muy básica ProGuard para Android:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

Así que podría ahorrar que a un archivo, a continuación, llamar ProGuard de hormiga, que pasa en su JAR acaba de compilar y el JAR plataforma Android que está utilizando.

Ver también los ejemplos en el manual ProGuard.


Actualizar (4,5 años más tarde): Hoy en día utilicé Madera para Android de registro.

No sólo es un poco mejor que la implementación Log por defecto - la etiqueta de registro se establece de forma automática, y es fácil que entrar cuerdas y excepciones con formato -. Pero también se puede especificar diferentes comportamientos de registro en tiempo de ejecución

En este ejemplo, las declaraciones de registro sólo se puede escribir a LogCat en versiones de depuración de mi aplicación:

La madera se estableció en mi método Application onCreate():

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

A continuación, en cualquier otro lugar en mi código que pueda conectarse fácilmente:

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

Vea la muestra de la Madera aplicación para un ejemplo más avanzado, donde se envían todas las declaraciones de registro para logCat durante el desarrollo y en la producción, no hay instrucciones de depuración está en el sistema, pero los errores se informan en silencio a Crashlytics.

Otros consejos

Todas las buenas respuestas, pero cuando había terminado con mi desarrollo que no querían para cualquiera que use si las declaraciones alrededor de todo el registro de llamadas, ni quería utilizar herramientas externas.

Así que la solución yo estoy usando es reemplazar la clase android.util.Log con mi propia clase 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);
    }
}

Lo único que tenía que hacer en todos los archivos de origen fue la de sustituir la importación de android.util.Log con mi propia clase.

I sugieren tener un valor booleano estático en algún lugar que indica si o no a log:

class MyDebug {
  static final boolean LOG = true;
}

A continuación, siempre que desea iniciar sesión en el código, simplemente hacer esto:

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

Ahora cuando se establece en false MyDebug.LOG, el compilador se tira a todo el código dentro de dichos controles (ya que es un static final, se conoce en tiempo de compilación que el código no se utiliza.)

Para proyectos más grandes, es posible que desee comenzar a tener booleanos en archivos individuales para poder fácilmente habilitar o deshabilitar el registro no es necesario. Por ejemplo, éstas son las diversas constantes de registro que tenemos en el gestor de ventanas:

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 el código correspondiente como:

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

Proguard solución de Christopher es el mejor, pero si por alguna razón no le gusta Proguard, aquí es una solución muy baja tecnología:

registros Comentario:

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

logs Descomente:

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

Una restricción es que sus instrucciones de registro no deben abarcar varias líneas.

(ejecutar estas líneas en una cáscara de UNIX en la raíz de su proyecto. Si utiliza Windows, obtener una capa UNIX o utilizar los comandos equivalente de Windows)

Me gustaría añadir algunas precisiones sobre el uso Proguard con Android Studio y Gradle, ya que tenía un montón de problemas para eliminar las líneas de registro desde el binario final.

Con el fin de hacer assumenosideeffects en Proguard trabaja, no es un requisito previo.

En el archivo Gradle, tiene que especificar el uso de la proguard-android-optimize.txt como archivo predeterminado.

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 realidad, en el archivo proguard-android.txt defecto, la optimización se desactiva con las dos banderas:

-dontoptimize
-dontpreverify

El archivo proguard-android-optimize.txt no agrega esas líneas, por lo que ahora pueden trabajar assumenosideeffects.

A continuación, personalmente, utilizo SLF4J , tanto más cuando desarrollo algunas bibliotecas que se distribuyen a los demás . La ventaja es que por defecto no hay salida. Y si el integrador quiere algunas salidas de registro, que puede Logback utiliza para Android y activar los registros, por lo que los registros se puede redirigir a un archivo o al LogCat.

Si realmente necesito para despojar a los registros de la biblioteca final, a continuación, añadir a mi archivo Proguard (después de haber activado el archivo proguard-android-optimize.txt por supuesto):

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

Yo recomiendo el uso de la Madera proveniente de Jake Wharton

https://github.com/JakeWharton/timber

se resuelve el problema con la activación/desactivación de plus añade la etiqueta de clase automágicamente

sólo

public class MyApp extends Application {

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

los registros sólo se utiliza en la depuración de ver y, a continuación, utilizar

Timber.d("lol");

o

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

para imprimir

"Su clase / msg" sin specyfing la etiqueta

He utilizado un clase LogUtils como en el ejemplo de aplicación Google IO. He modificado esto para utilizar una constante DEBUG específico de la aplicación en lugar de BuildConfig.DEBUG porque BuildConfig .debug no es fiable . Luego, en mis clases tengo el siguiente.

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

Me gustaría considerar el uso de facilidad de registro de roboguice en lugar de la incorporada en el androide .util.Log

Su instalación desactiva automáticamente la depuración y registros detallados de las versiones de lanzamiento. Además, obtiene algunas características ingeniosas para libre (por ejemplo, comportamiento de registro personalizable, datos adicionales para cada registro y más)

El uso Proguard podría ser bastante complicado y no me gustaría pasar por la molestia de configurar y hacer que trabajo con su solicitud a menos que tenga una buena razón para ello (desactivación de registros no es una buena)

Quiero poner esta solución que se aplica específicamente para los usuarios de Android Studio. También he descubierto recientemente, madera aserrada y han importado con éxito en mi aplicación de la siguiente manera:

Ponga la versión más reciente de la biblioteca en tu build.gradle:

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

A continuación, en Android Studios, vaya a Editar -> Buscar -> Reemplazar en Camino ...

Tipo de Log.e(TAG, o como se haya definido sus mensajes de registro en el cuadro de texto "Text to find". A continuación, sólo se sustituya por Timber.e(

 introducir descripción de la imagen aquí

Haga clic en Buscar y luego vuelva a colocar todos.

Android Estudios ahora pasará a través de todos sus archivos en su proyecto y reemplazar todos los registros con los Timbers.

El único problema que tuve con este método es que Gradle viene hasta conuna millón de mensajes de error después porque no puede encontrar "Sal" en las importaciones para cada uno de los archivos Java. Basta con hacer clic sobre los errores y Android Estudios importará automáticamente "Sal" en su java. Una vez que lo ha hecho para los archivos de todos sus errores, Gradle compilará de nuevo.

También es necesario poner este fragmento de código en su método onCreate de la clase Application:

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

Esto dará como resultado el registro de aplicación sólo cuando se está en el modo de desarrollo no está en producción. Usted también puede tener BuildConfig.RELEASE para iniciar la sesión en modo de lanzamiento.

Por android.util.Log proporciona una manera de activar / desactivar el registro:

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

Por defecto el método isLoggable (...) devuelve falso, sólo después de que SetProp en el dispositivo le gusta esto:

adb shell setprop log.tag.MyAppTag DEBUG

Significa cualquier registro por encima nivel de depuración se puede imprimir. Referencia doc androide:

  

Comprueba si o no un registro para la etiqueta especificada es registrable en el nivel especificado. El nivel predeterminado de cualquier variable se pone   a INFO. Esto significa que cualquier nivel por encima e incluyendo INFO será   iniciado sesión. Antes de realizar ninguna llamada a un método de registro debe comprobar   para ver si su etiqueta debe estar conectado. Puede cambiar el nivel predeterminado   mediante el establecimiento de una propiedad del sistema: 'log.tag setprop. '   Donde el nivel es o bien detallado, DEBUG, INFO, WARN, ERROR, afirman, o   REPRIMIR. SUPRIMIR se apagará todo el registro de su etiqueta. Usted puede   También crear un archivo que local.prop con la siguiente en él:   'Log.tag. =' Y lugar que en /data/local.prop.

Así que podríamos usar a medida util log:

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 puede ejecutar un reemplazo global (una vez), y después de que preservan una convención de codificación, se puede seguir el patrón de uso frecuente en Android marco .

En lugar de escribir

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

tenerlo como

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

Ahora Proguard puede quitar el StringBuilder y todas las cadenas y los métodos que utiliza en el camino, desde la liberación optimizada DEX. Utilice proguard-android-optimize.txt y usted no tiene que preocuparse por android.util.Log en su proguard-rules.pro:

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

Con Android Studio plug-in Gradle, BuildConfig.DEBUG es bastante fiable, por lo que no es necesario constantes adicionales para controlar la extracción.

Tengo una solución muy simple. Yo uso IntelliJ para el desarrollo, por lo que los detalles varían, pero la idea se aplicará en todos los IDE de.

tomo a raíz de mi árbol de fuentes, haga clic derecho y seleccionar a hacer "reemplazar". entonces elijo para reemplazar todo "Log". con "// registro.". Esto elimina todas las declaraciones de registro. Para poner de nuevo más tarde repito la misma reemplazar pero esta vez como reemplazar todos "// registro." con "Log.".

Los trabajos apenas grande para mí. Sólo recuerde que debe establecer el reemplazo si fuera mayúsculas y minúsculas para evitar accidentes tales como "diálogo.". Para seguridad adicional también se puede hacer con el primer paso "Log". como la cadena de búsqueda.

brillante.

Como El comentario de zserge sugirió,

  

La madera es muy agradable, pero si ya tiene un proyecto existente - se puede tratar github.com/zserge/log. Es una gota en el reemplazo para android.util.Log y tiene la mayor parte de las características que la madera ha y aún más.

su biblioteca registro proporciona sencilla activar / desactivar el interruptor de la impresión del Registro de la siguiente manera.

Además, solamente requiere para cambiar las líneas import, y no tiene que cambiar para la declaración 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

Añadir siguiente a su Proguard-rules.txt archivo

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

introducir descripción de la imagen aquí

Esto es lo que solía hacer en mis proyectos androide ..

En Android Studio podemos hacer operación similar por, Ctrl + Shift + F para encontrar desde todo el proyecto (+ Shift Comando + F en MacOs) y Ctrl + Shift + R para Reemplazar ((Ctrl + Shift + R en MacOs) )

he mejorado en la solución anterior mediante el apoyo a diferentes niveles de registro y por el cambio de los niveles de registro de forma automática dependiendo de si el código se ejecuta en un dispositivo en vivo o en el emulador.

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 hará por usted en su comunicado de acumulación y ahora las buenas noticias de android.com:

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

La herramienta ProGuard se reduce, optimiza y ofusca su código mediante la eliminación de código no utilizado y cambiar el nombre de las clases, campos y métodos con los nombres semánticamente oscuros. El resultado es un archivo APK de tamaño más pequeño que es más difícil de realizar ingeniería inversa. Debido ProGuard hace que su aplicación más difícil de realizar ingeniería inversa, es importante que lo utilice cuando su aplicación utiliza características que son sensibles a la seguridad como cuando usted obtiene licencia para sus aplicaciones.

ProGuard está integrado en el sistema de construcción de Android, por lo que no tiene que invocar de forma manual. ProGuard sólo se ejecuta cuando se genera la aplicación en modo de lanzamiento, por lo que no tiene que tratar con código ofuscado cuando se genera la aplicación en modo de depuración. Después de dirigir el ProGuard es completamente opcional, pero muy recomendable.

Este documento describe cómo activar y configurar ProGuard, así como utilizar la herramienta de retroceso para decodificar seguimientos de pila ofuscado

Me gusta usar Log.d (TAG, un trozo de cuerda, a menudo un String.Format ()).

TAG es siempre el nombre de la clase

Transformar Log.d (TAG, -> LOGD (en el texto de su clase

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

De este modo, cuando esté listo para hacer una versión de lanzamiento, fijado a MainClass.debug falsa!

Registros se pueden eliminar con golpe en Linux y sed:

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

Funciona para los registros de varias líneas. En esta solución puede estar seguro, que los registros no están presentes en el código de producción.

Sé que esto es una vieja pregunta, pero ¿por qué no se reemplaza todo el registro de llamadas con algo como Boolean logCallWasHere = true; // --- resto de su registro aquí

Es por esto que usted sabrá cuando se quiere poner de nuevo, y no van a afectar su si la llamada declaración:)

¿Por qué no hacer

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

? No hay bibliotecas adicionales necesarios, no hay reglas Proguard que tienden a arruinar el proyecto y el compilador de Java se acaba de dejar de lado el código de bytes de la presente convocatoria cuando haces versión de lanzamiento.

la forma más sencilla;

uso DebugLog

Todos los registros están desactivados por DebugLog cuando se libera la aplicación.

https://github.com/MustafaFerhan/DebugLog

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top