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?
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.
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>
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).
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>
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