2011-08-17 4 views
20

Eventuali duplicati:
Removing unused strings during ProGuard optimisationRimozione registrazione con ProGuard non rimuovere le corde essere registrati

Ho un'applicazione Android con decine di dichiarazioni di registrazione. Preferirei che non apparirebbero nella versione, quindi ho usato Proguard con qualcosa di simile nel file proguard.cfg:

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

ma il problema è che ci sono un sacco di Log.d("something is " + something), e anche se la Log.d() la dichiarazione viene rimossa dal bytecode, , le stringhe sono ancora presenti.

Così, seguendo this risposta, ho creato una semplice classe wrapper, qualcosa sulla falsariga di:

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

Poi ho modificato il mio proguard.cfg:

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

Ma le corde si trovano ancora nel bytecode generato!

Oltre a ciò, sto utilizzando lo standard proguard.cfg fornito dall'SDK di Android. Sto facendo qualcosa di sbagliato?


Edit: dopo aver esaminato il bytecode generato, ho visto che le corde erano lì, ma non erano di essere aggiunto uno all'altro, come pensavo. Erano memorizzati in un array. Perché? Passarli come parametri variabili al mio metodo. Sembra ProGuard non piace che, così ho modificato la mia classe logger in questo modo:

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

E 'brutto, ma ora le stringhe sono nessuna parte nel bytecode.

È una specie di bug/limitazione di ProGuard? O semplicemente non capisco come funziona?

+0

Si potrebbe voler evitare gli hack proguard e basta usare una costante: http://stackoverflow.com/questions/4199563/android-util-log-when-publishing-what-can-i-do-not-do If allora usi un proguard costante rimuoverà le linee di codice quando == false. – Blundell

+2

È vero che questo è un hack, e un brutto, ma penso che sia meglio che mettere "if (DEBUG)" ovunque. Il codice risultante è più pulito e il risultato è lo stesso nell'applicazione esportata. Inoltre, per qualche ragione, Eclipse si lamenta del codice morto se la costante di debug è falsa e non mi piace. Grazie per l'idea, però :) –

+0

Si noti che potrebbe esserci ancora un codice morto se si superano i tipi di dati di base. Proguard non rimuove il tipo di dati di base alla corrispondente conversione 'Object'. Per esempio. se passi un 'int', Proguard lascerà nella riga' Integer.valueOf (someVar); ' – crazymaik

risposta

11

La soluzione con diversi metodi per diversi numeri di argomenti è probabilmente la più comoda. Un singolo metodo con un numero variabile di argomenti sarebbe più bello, ma la versione corrente di ProGuard non è abbastanza intelligente da rimuovere tutto il codice inutilizzato.

Il compilatore java compila un numero variabile di argomenti come un singolo argomento di matrice. Dal lato dell'invocazione, ciò significa creare una matrice delle giuste dimensioni, compilare gli elementi e passarli al metodo. ProGuard rileva che l'array viene creato e quindi utilizzato per memorizzare elementi in esso. Non si rende conto (ancora) che quindi non viene utilizzato per le effettive operazioni utili, con l'invocazione del metodo scomparsa. Di conseguenza, la creazione e l'inizializzazione dell'array vengono mantenute.

È consigliabile verificare il codice elaborato se si prevede un'ottimizzazione particolare.

+1

Ho appena iniziato a usare pro guard per rimuovere i log e sto affrontando lo stesso problema di dead code. Mi chiedo perché Pro Guard non sia in grado di rimuovere questi array nei passaggi successivi. Ho visto IDE sottolineando che una variabile locale non viene mai utilizzata. Quindi, certamente sembra possibile. –

4

Proguard non mi funziona, troppo, e non mi piace per creare un wrapper registro, così ho verificato le seguenti soluzioni:

soluzione di lavoro

final static boolean IsDebugging = false; 

e nel codice:

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

ritengono che è necessario utilizzare finale parola chiave in modo che ISDE il bugging diventa vero o falso in fase di compilazione e le stringhe di log non appaiono nel bytecode finale.

NON FUNZIONA (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; 
} 

e nel mio codice:

boolean IsDebugging = Utils.IsDebugMode(this); 

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

La soluzione di cui sopra non stampare qualsiasi Entra Logcat ma la stringa di registro sono compilati ed esistono in bytecode finale che è cattivo.

L'altra soluzione era:

NON FUNZIONANTE (BuildConfid.DEBUG)

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

Questo è lo stesso come soluzione IsDebugMode. Non stampa nulla ma le stringhe sono in bytecode finale. Male di nuovo!

+0

Si prega di vedere il secondo commento della mia domanda. –