Usuwanie nieużywanych ciągów podczas optymalizacji ProGuard

Dołączam tę konfigurację ProGuard , aby usunąć instrukcje dziennika debugowania po wydaniu aplikacji na Androida:

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

To działa zgodnie z oczekiwaniami-widzę z logów ProGuard i wyjścia dziennika Androida, że połączenia takie jak Log.d("This is a debug statement"); są usuwane.

Jednak, jeśli dekompiluję aplikację na tym etapie, nadal mogę zobaczyć wszystkie litery String, które zostały użyte - np. This is a debug statement w tym przykładzie.

Czy istnieje sposób na usunięcie każdego String, który nie jest już potrzebny z bytecode?

Author: Community, 2011-05-15

4 answers

ProGuard może usunąć Proste Stałe argumenty (ciągi znaków, liczby całkowite itp.). Tak więc w tym przypadku kod i stała łańcuchowa powinny zniknąć całkowicie:

Log.d("This is a debug statement");

Możesz jednak zaobserwować problem z jakimś kodem takim jak:

Log.d("The answer is "+answer);

Po kompilacji odpowiada to:

Log.d(new StringBuilder().append("The answer is ").append(answer).toString());

ProGuard w wersji 4.6 może uprościć to do czegoś takiego jak:

new StringBuilder().append("The answer is ").append(answer).toString();

Więc logowanie zniknęło, ale krok optymalizacji wciąż pozostawia trochę puchu. On zaskakująco trudne do uproszczenia bez głębszej wiedzy o klasie StringBuilder. Jeśli chodzi o ProGuard, można powiedzieć:

new DatabaseBuilder().setup("MyDatabase").initialize(table).close();

Dla człowieka, Kod Stringbuildera można oczywiście usunąć, ale kod bazy danych prawdopodobnie nie może. ProGuard wymaga analizy ucieczki i kilku innych technik, których nie ma jeszcze w tej wersji.

Jeśli chodzi o rozwiązanie: możesz utworzyć dodatkowe metody debugowania, które przyjmują proste argumenty i pozwolić ProGuard usunąć te:

MyLog.d("The answer is ", answer);

Alternatywnie, możesz spróbować prefiksować każdą instrukcję debug z warunkiem, który ProGuard może później ocenić jako false. Ta opcja może być nieco bardziej zawiła, wymagając dodatkowej opcji-assumenosideeffects na metodzie inicjalizacji znacznika debug.

 46
Author: Eric Lafortune,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-16 21:12:02

Oto Jak to robimy-używając zadania ant

<target name="base.removelogs">
    <replaceregexp byline="true">
        <regexp pattern="Log.d\s*\(\s*\)\s*;"/>
        <substitution expression="{};"/>
        <fileset dir="src/"><include name="**/*.java"/></fileset>
    </replaceregexp>
</target>
 6
Author: nir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-16 11:54:18

Ponieważ nie mam wystarczająco dużo rep, aby skomentować odpowiedź zadania ant bezpośrednio, tutaj kilka poprawek do niego, ponieważ okazuje się to bardzo pomocne w połączeniu z serwerem CI, takim jak Jenkins, który może wykonać go dla kompilacji wydania:

<target name="removelogs">
    <replaceregexp byline="true">
        <regexp pattern="\s*Log\.d\s*\(.*\)\s*;"/>
        <substitution expression="{};"/>
        <fileset dir="src">
            <include name="**/*.java"/>
        </fileset>
    </replaceregexp>
</target>

"."po Log musi być uciekł i".'wewnątrz nawiasów odnosi się do każdej instrukcji logowania, a nie tylko do spacji, jak robi to' \ s*'.

Ponieważ nie mam dużego doświadczenia z RegEx mam nadzieję, że pomoże to niektórym osobom w tej samej sytuacji, aby uzyskać tę mrówkę zadanie pracujące (np. na Jenkinsie).

 5
Author: utopius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-11 21:45:39

Jeśli chcesz obsługiwać wieloliniowe połączenia dziennika, możesz użyć tego wyrażenia regularnego:

(android\.util\.)*Log\.@([ewidv]|wtf)\s*\([\S\s]*?\)\s*;

Powinieneś być w stanie użyć tego w ramach zadania ant replaceregexp w następujący sposób:

<replaceregexp>
    <regexp pattern="((android\.util\.)*Log\.([ewidv]|wtf)\s*\([\S\s]*?\)\s*;)"/>
    <substitution expression="if(false){\1}"/>
    <fileset dir="src/">
        <include name="**/*.java"/>
    </fileset>
</replaceregexp>

Uwaga: To otacza wywołania dziennika za pomocą if(false){ i }, więc oryginalne wywołanie jest zachowywane, zarówno w celach informacyjnych, jak i w celu zachowania numerów linii podczas sprawdzania pośrednich plików kompilacji, co pozwala kompilatorowi Javy usunąć wywołania podczas kompilacji.

Jeśli wolisz całkowicie usunąć połączenia dziennika, możesz można tak zrobić:

<replaceregexp>
    <regexp pattern="(android\.util\.)*Log\.([ewidv]|wtf)\s*\([\S\s]*?\)\s*;"/>
    <substitution expression=""/>
    <fileset dir="src/">
        <include name="**/*.java"/>
    </fileset>
</replaceregexp>

Można również zastosować Wyrażenie regularne jako filtr w <copy> zadanie jak tak:

<copy ...>
    <fileset ... />
    <filterchain>
        <tokenfilter if:true="${strip.log.calls}">
            <stringtokenizer delims=";" includeDelims="true"/>
            <replaceregex pattern="((android\.util\.)*Log\.([ewidv]|wtf)\s*\([\S\s]*?\)\s*;)" replace="if(false){\1}"/>
        </tokenfilter>
    </filterchain>
    <!-- other-filters-etc -->
</copy>
 0
Author: Lorne Laliberte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-17 03:59:47