2011-08-17 7 views
20

Duplicar posible:
Removing unused strings during ProGuard optimisationExtracción de registro con ProGuard no retire las cuerdas están registrando

Tengo una aplicación Android con decenas de declaraciones de registro. Yo prefiero que no aparecerían en la versión de lanzamiento, por lo que utiliza Proguard con algo como esto en el archivo proguard.cfg:

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

Pero el problema es que hay una gran cantidad de Log.d("something is " + something), y aunque el Log.d() la instrucción se está eliminando del bytecode, las cadenas todavía están allí.

Así que, siguiendo this respuesta, he creado una clase de contenedor simple, algo a lo largo de las líneas de:

public class MyLogger { 
    public static void d(Object... msgs) { 
     StringBuilder log = new StringBuilder(); 
     for(Object msg : msgs) { 
      log.append(msg.toString()); 
     } 
     Log.d(TAG, log.toString()); 
    } 
} 

Entonces editado mi proguard.cfg:

-assumenosideeffects class my.package.MyLogger { 
    public static *** d(...); 
} 

Pero las cadenas todavía se encuentran en el bytecode generado!

Aparte de esto, estoy usando el estándar proguard.cfg provisto por el SDK de Android. ¿Estoy haciendo algo mal?


Editar: después de examinar el código de bytes generado, vi que las cuerdas estaban allí, pero no se les está siendo agregado a los otros, como yo pensaba. Estaban siendo almacenados en una matriz. ¿Por qué? Para pasarlos como parámetros variables a mi método. Parece que ProGuard no le gusta eso, así que modificó mi clase registrador de la siguiente manera:

public static void d(Object a) { 
    log(a); 
} 

public static void d(Object a, Object b) { 
    log(a, b); 
} 

(... I had to put like seven d() methods ...) 

private static void log(Object... msgs) { 
    (same as before) 
} 

Es feo, pero ahora las cuerdas son ninguna parte en el código de bytes.

¿Es esto algún tipo de error/limitación de ProGuard? ¿O simplemente no estoy entendiendo cómo funciona?

+0

Es posible que desee evitar hackers proguard y simplemente usar una constante: http://stackoverflow.com/questions/4199563/android-util-log-when-publishing-what-can-i-do-not-do If a continuación, utilice un proguard constante eliminará las líneas de código cuando == falso. – Blundell

+2

Es cierto que este es un truco, y uno feo, pero creo que es mejor que poner 'if (DEBUG)' en todas partes. El código resultante es más limpio y el resultado es el mismo en la aplicación exportada. Además, por alguna razón, Eclipse gime sobre el código muerto si la constante de depuración es falsa, y eso no me gusta. Gracias por la idea, aunque :) –

+0

Tenga en cuenta que todavía puede haber algún código muerto si pasa tipos de datos básicos. Proguard no elimina el tipo de datos básico a la conversión 'Objeto' correspondiente. P.ej. si pasa un 'int', Proguard saldrá en la línea' Integer.valueOf (someVar); ' – crazymaik

Respuesta

11

Su solución con diferentes métodos para diferentes números de argumentos es probablemente la más conveniente. Un único método con una cantidad variable de argumentos sería más agradable, pero la versión actual de ProGuard no es lo suficientemente inteligente como para eliminar todo el código no utilizado.

El compilador de Java compila una cantidad variable de argumentos como un solo argumento de matriz. En el lado de la invocación, esto significa crear una matriz del tamaño correcto, completar los elementos y pasarlo al método. ProGuard ve que la matriz se está creando y luego se está usando para almacenar elementos en ella. No se da cuenta (todavía) de que no se usa para operaciones útiles reales, con la invocación del método desaparecida. Como resultado, se conserva la creación e inicialización de la matriz.

Es una buena práctica verificar el código procesado si está esperando alguna optimización en particular.

+1

Acabo de comenzar a utilizar pro guard para eliminar los registros y estoy enfrentando el mismo problema de código muerto. Me pregunto por qué el guardia profesional no puede eliminar estas matrices en pases posteriores. He visto IDE señalando que una variable local nunca se usa. Por lo tanto, ciertamente parece posible. –

4

Proguard no me funciona, también, y no me gusta para crear una envoltura alrededor de registro, por lo que he probado las siguientes soluciones:

solución de trabajo

final static boolean IsDebugging = false; 

y en el código:

if(IsDebugging) 
    Log.i(TAG, "Debugging"); 

consideran que debe utilizar última palabra clave para que ISDE las escuchas se convierten en verdaderas o falsas en el tiempo de compilación y las cadenas de registro no aparecen en el bytecode final.

NO TRABAJO (IsDebugMode)

public static boolean IsDebugMode(Context context) { 
    PackageManager pm = context.getPackageManager(); 
    PackageInfo pi; 
    try { 
     pi = pm.getPackageInfo(context.getPackageName(),0); 
    } catch (NameNotFoundException e) { 
     return false; 
    } 
    return (pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; 
} 

y en mi código:

boolean IsDebugging = Utils.IsDebugMode(this); 

    if(IsDebugging) 
     Log.i(TAG, "Debugging"); 

La solución anterior no imprime ninguna Acceder Logcat pero la cadena de registro se compilan y existen en código de bytes final que es malo.

La otra solución era:

NO de trabajo (BuildConfid.DEBUG)

if(BuildConfig.DEBUG) 
     Log.i(TAG, "Debugging"); 

Esta es la misma que la solución IsDebugMode. No imprime nada, pero las cadenas están en bytecode final. Malo de nuevo!

+0

Consulte el segundo comentario de mi pregunta. –

Cuestiones relacionadas