ProGuard-壓縮-混淆

ProGuard是一個Java類文件壓縮器、優(yōu)化器、混淆器和預校驗器。

壓縮步驟檢測并刪除未使用的類、字段、方法和屬性。優(yōu)化步驟分析和優(yōu)化方法的字節(jié)碼。混淆步驟使用無意義的簡短名稱重命名其余的類、字段和方法。這些第一步使代碼庫更小、更高效,并且更難進行反向工程。最后一個預驗證步驟將預驗證信息添加到類中,這是Java微版本所必需的,或者可以縮短Java 6的啟動時間。

這些步驟都是可選的。例如,ProGuard還可以僅用于列出應用程序中的死代碼,或者用于預驗證類文件,以便在Java 6中高效使用。

proguard1.png

ProGuard通常讀取輸入jar(或war、ear、zip或目錄)。然后它會收縮、優(yōu)化、混淆和預先驗證它們??蛇x地,可以執(zhí)行多個優(yōu)化傳遞,每個優(yōu)化傳遞之后通常會執(zhí)行另一個收縮步驟。ProGuard將處理后的結果寫入一個或多個輸出jar(或war、ear、zips或目錄)。輸入可能包含資源文件,其名稱和內容可以選擇性地進行更新,以反映混淆的類名。

ProGuard需要指定輸入jar的庫jar(或war、ear、zip或目錄)。這些基本上是編譯代碼所需的庫。ProGuard使用它們重構正確處理所需的類依賴項。庫jar本身始終保持不變。您仍然應該將它們放在最終應用程序的類路徑中。

入口點

為了確定哪些代碼必須保留,哪些代碼可以丟棄或混淆,必須為代碼指定一個或多個入口點。這些入口點通常是帶有主方法、applet、midlet等的類。

  • 在收縮步驟中,ProGuard從這些種子開始,遞歸地確定使用哪些類和類成員。所有其他類和類成員都將被丟棄。
  • 在優(yōu)化步驟中,ProGuard進一步優(yōu)化代碼。在其他優(yōu)化中,可以將非入口點的類和方法設置為私有的、靜態(tài)的或最終的,可以刪除未使用的參數,并且可以內聯一些方法。
  • 在混淆步驟中,ProGuard重命名不是入口點的類和類成員。在整個過程中,保留入口點可以確保仍然可以通過它們的原始名稱訪問它們。
  • 預驗證步驟是唯一不需要知道入口點的步驟。

本手冊的使用部分描述了必要的-keep選項,示例部分提供了大量示例。

反射

對于任何代碼的自動處理,反射和內省都會帶來特定的問題。在ProGuard中,動態(tài)創(chuàng)建或調用(即按名稱)的代碼中的類或類成員也必須指定為入口點。例如,class . forname()構造可以在運行時引用任何類。通常不可能預知必須保留哪些類(使用它們的原始名稱),因為類名可能從配置文件中讀取,例如。因此,必須在ProGuard配置中使用相同的-keep選項指定它們。
但是,ProGuard已經為您檢測并處理以下情況:

  • Class.forName("SomeClass")
  • SomeClass.class
  • SomeClass.class.getField("someField")
  • SomeClass.class.getDeclaredField("someField")
  • SomeClass.class.getMethod("someMethod", new Class[] {})
  • SomeClass.class.getMethod("someMethod", new Class[] { A.class })
  • SomeClass.class.getMethod("someMethod", new Class[] { A.class, B.class })
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[] {})
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class })
  • SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class, B.class })
  • AtomicIntegerFieldUpdater.newUpdater(SomeClass.class, "someField")
  • AtomicLongFieldUpdater.newUpdater(SomeClass.class, "someField")
  • AtomicReferenceFieldUpdater.newUpdater(SomeClass.class, SomeType.class, "someField")

類和類成員的名稱當然可能不同,但是構造應該完全相同,這樣ProGuard才能識別它們。引用的類和類成員保存在收縮階段,字符串參數在混淆階段正確更新。
此外,如果有必要保留一些類或類成員,ProGuard將提供一些建議。例如,ProGuard會注意到這樣的構造:“(SomeClass)Class.forName(variable). newinstance()”。這可能表明類或接口的SomeClass和/或其實現可能需要保留。然后可以相應地調整配置。

要獲得適當的結果,您至少應該對正在處理的代碼有一定程度的熟悉。執(zhí)行大量反射的混淆代碼可能需要反復試驗,特別是在沒有關于代碼內部結構的必要信息的情況下。

Keep 可選項

-keep [,modifier,...] class_specification

指定要保留為代碼入口點的類和類成員(字段和方法)。例如,為了保留應用程序,可以指定主類及其主方法。為了處理庫,您應該指定所有可公開訪問的元素。

-keepclassmembers [,modifier,...] class_specification

指定要保留的類成員(如果它們的類也被保留的話)。例如,您可能希望保留實現Serializable接口的類的所有序列化字段和方法。

-keepclasseswithmembers [,modifier,...] class_specification

指定要保留的類和類成員,條件是所有指定的類成員都存在。例如,您可能希望保留所有具有 main 方法的應用程序,而不需要顯式地列出它們。

-keepnames class_specification

-keep, allowclass_specification 的縮寫

指定要保留其名稱的類和類成員(如果在收縮階段沒有刪除這些名稱)。例如,您可能希望保留實現Serializable接口的類的所有類名,以便處理后的代碼與任何最初序列化的類保持兼容。完全不使用的類仍然可以被刪除。僅適用于模糊。

keepclassmembernames class_specification
  • keepembers,allowshrinking class_specification 的縮寫

指定要保留其名稱(如果在收縮階段沒有刪除這些名稱)的類成員。例如,在處理JDK 1.2或更早版本編譯的庫時,您可能希望保留合成類$ methods的名稱,這樣在處理使用處理過的庫的應用程序時,混淆器可以再次檢測它(盡管ProGuard本身不需要這個)。僅適用于模糊。

-keepclasseswithmembernames class_specification

-keepclasseswithmembers,allowshrinking class_specification 的縮寫

指定要保留其名稱的類和類成員,條件是在收縮階段之后所有指定的類成員都出現。例如,您可能希望保留所有 native 方法名稱及其類的名稱,以便處理后的代碼仍然可以鏈接到本機庫代碼。完全不使用的本地方法仍然可以被刪除。如果使用了類文件,但是沒有使用它的本機方法,那么它的名稱仍然是模糊的。僅適用于模糊。

-printseeds [filename]

指定詳細列出由各種-keep選項匹配的類和類成員。列表被打印到標準輸出或給定文件中。如果確實找到了想要的類成員,特別是在使用通配符的情況下,這個列表非常有用。例如,您可能想要列出您保存的所有應用程序或所有applet。

壓縮 可選項

-dontshrink

指定不壓縮輸入類文件。默認情況下,應用是開啟壓縮的;所有類和類成員都被刪除,除了各種-keep選項列出的類和它們直接或間接依賴的類。在每個優(yōu)化步驟之后還應用收縮步驟,因為一些優(yōu)化可能會刪除更多的類和類成員。

-printusage [filename]

指定列出輸入類文件的死代碼。列表被打印到標準輸出或給定文件中。例如,您可以列出應用程序未使用的代碼。僅適用于開啟壓縮時。

-whyareyoukeeping class_specification

指定打印有關為什么在收縮步驟中保留給定類和類成員的詳細信息。如果您想知道為什么輸出中會出現某些給定的元素,那么這將非常有用。一般來說,有很多不同的原因。此選項為每個指定的類和類成員將最短的方法鏈打印到指定的種子或入口點。在當前實現中,打印出來的最短鏈有時可能包含循環(huán)扣除額——這些扣除額并不反映實際的收縮過程。如果指定-verbose選項,則跟蹤包含完整的字段和方法簽名。僅適用于開啟壓縮時。

優(yōu)化 可選項

-dontoptimize

指定不優(yōu)化輸入類文件。默認情況下,優(yōu)化是啟用的;所有方法都在字節(jié)碼級別上進行了優(yōu)化。

-optimizations optimization_filter

在更細粒度的級別上指定要啟用和禁用的優(yōu)化。僅適用于優(yōu)化時。這是一個專家的選擇。

-optimizationpasses n

指定要執(zhí)行的優(yōu)化傳遞的次數。默認情況下,只執(zhí)行一次傳遞。多次傳遞可能會導致進一步的改進。如果優(yōu)化通過后沒有發(fā)現任何改進,則優(yōu)化結束。僅適用于優(yōu)化時。

-assumenosideeffects class_specification

指定在處理過程中可以擴展類和類成員的訪問修飾符。這可以改善優(yōu)化步驟的結果。例如,在內聯公共getter時,可能還需要將訪問的字段也變?yōu)楣驳?。盡管Java的二進制兼容性規(guī)范在形式上不要求這樣做(cfr)。Java語言規(guī)范,第二版,第13.4.6節(jié)),一些虛擬機將有問題的處理代碼,否則。僅適用于優(yōu)化時(以及使用-repackageclasses選項混淆時)。
反指示:在處理要用作庫的代碼時,可能不應該使用此選項,因為在API中設計為非公共的類和類成員可能會變成公共的。

-mergeinterfacesaggressively

指定可以合并接口,即使接口的實現類沒有實現所有接口方法。這可以通過減少類的總數來減少輸出的大小。注意,Java的二進制兼容性規(guī)范允許這樣的構造(cfr)。Java語言規(guī)范,第二版,第13.5.3節(jié)),即使它們在Java語言中是不允許的(cfr)。Java語言規(guī)范,第二版,第8.1.4節(jié))。僅適用于優(yōu)化時。

反指示:設置此選項會降低某些jvm上處理的代碼的性能,因為高級即時編譯傾向于使用較少實現類的更多接口。更糟糕的是,一些jvm可能無法處理生成的代碼。值得注意的是:

Sun的JRE 1.3在一個類中遇到超過256個Miranda方法(沒有實現的接口方法)時,可能會拋出一個內部錯誤。

混淆 可選項

-dontobfuscate

指定不混淆輸入類文件。默認情況下,應用混淆;類和類成員接收新的短隨機名稱,但不同的-keep選項列出的名稱除外。刪除對調試有用的內部屬性,如源文件名、變量名和行號。

-printmapping [filename]

指定為已重命名的類和類成員打印從舊名稱到新名稱的映射。映射被打印到標準輸出或給定文件中。例如,對于后續(xù)的增量混淆,或者如果您希望再次理解混淆的堆棧跟蹤,就需要使用它。僅適用于開啟混淆。

-applymapping filename

指定重用在前一次混淆運行ProGuard時打印出的給定名稱映射。映射文件中列出的類和類成員接收與其一起指定的名稱。未提及的類和類成員將接收新名稱。映射可以引用輸入類和庫類。此選項對于增量混淆非常有用,即處理現有代碼片段的外接程序或小補丁。在這種情況下,您應該考慮是否還需要選項—使用uniqueclassmembernames。只允許一個映射文件。僅適用于開啟混淆。

-obfuscationdictionary filename

指定一個文本文件,其中所有有效單詞都用作混淆字段和方法名稱。默認情況下,短名稱如“a”、“b”等用作混淆的名稱。通過使用混淆字典,您可以指定保留的關鍵字列表,或者具有外部字符的標識符。空格、標點符號、重復單詞和#符號后的注釋將被忽略。請注意,混淆字典很難改善混淆。優(yōu)秀的編譯器可以自動替換它們,通過使用更簡單的名稱再次混淆,可以相當簡單地恢復效果。最有用的應用程序是指定通常已經出現在類文件中的字符串(如“代碼”),從而進一步減小類文件的大小。僅適用于開啟混淆。

-classobfuscationdictionary filename

指定一個文本文件,其中所有有效單詞都用作混淆類名。混淆字典類似于選項之一-混淆字典。僅適用于開啟混淆。

-packageobfuscationdictionary filename

指定一個文本文件,其中所有有效的單詞都用作混淆的包名?;煜值漕愃朴谶x項之一-混淆字典。僅適用于開啟混淆。

-overloadaggressively

指定在混淆時應用主動重載。然后,多個字段和方法可以獲得相同的名稱,只要它們的參數和返回類型不同(不僅僅是它們的參數)。這個選項可以使處理后的代碼更小(更難以理解)。僅適用于開啟混淆。

反指示:生成的類文件屬于Java字節(jié)碼規(guī)范(cfr)。Java虛擬機規(guī)范,第二版,4.5節(jié)和4.6節(jié)的第一段),盡管這種重載在Java語言中是不允許的(cfr)。Java語言規(guī)范,第二版,8.3節(jié)和8.4.7節(jié))。盡管如此,一些工具仍然存在問題。

-useuniqueclassmembernames

指定將相同的混淆名稱分配給具有相同名稱的類成員,將不同的混淆名稱分配給具有不同名稱的類成員(針對每個給定的類成員簽名)。如果沒有這個選項,可以將更多的類成員映射到相同的短名稱,如“a”、“b”等。因此,該選項略微增加了生成的代碼的大小,但它確保在后續(xù)的增量混淆步驟中始終尊重保存的混淆名稱映射。

例如,考慮兩個不同的接口,其中包含具有相同名稱和簽名的方法。如果沒有此選項,這些方法可能在第一個混淆步驟中獲得不同的混淆名稱。如果隨后添加了一個包含實現這兩個接口的類的補丁,那么ProGuard將不得不在增量混淆步驟中為這兩個方法強制使用相同的方法名。原始的混淆代碼被更改,以保持生成的代碼一致。在初始混淆步驟中使用此選項,將永遠不需要進行此類重命名。

僅適用于開啟混淆。事實上,如果您計劃執(zhí)行增量混淆,您可能希望避免完全收縮和優(yōu)化,因為這些步驟可以刪除或修改代碼中對以后的添加非常重要的部分。

-dontusemixedcaseclassnames

指定在混淆時不要生成混合大小寫的類名。默認情況下,混淆的類名可以包含大寫字符和小寫字符的混合。這將創(chuàng)建完全可接受和可用的jar。只有在使用不區(qū)分大小寫的歸檔系統(tǒng)(例如Windows)在平臺上解壓縮jar時,解壓縮工具才可能讓名稱類似的類文件彼此覆蓋。解壓時自毀的代碼!真正想在Windows上解包jar的開發(fā)人員可以使用這個選項來關閉這個行為。請注意,混淆的jar將因此變得更大。僅適用于開啟混淆。

-keeppackagenames [package_filter]

指定不混淆給定的包名稱??蛇x過濾器是一個以逗號分隔的包名列表。包名可以包含?、*通配符,它們的前面可以有!非元件。僅適用于開啟混淆。

-flattenpackagehierarchy [package_name]

指定通過將重命名的所有包移動到給定的父包中來重新包裝它們。如果沒有參數或使用空字符串("),包將被移動到根包中。這個選項是進一步混淆包名稱的一個例子。它可以使處理后的代碼更小,更難以理解。僅適用于開啟混淆。

-repackageclasses [package_name]

指定通過將重命名的所有類文件移動到單個給定包中來重新打包。如果沒有參數或使用空字符串("),則該包將被完全刪除。此選項覆蓋-扁平化包層次結構選項。這是進一步混淆包名稱的另一個例子。它可以使處理后的代碼更小,更難以理解。它的棄用名稱是-defaultpackage。僅適用于開啟混淆。
反指示:如果將在包目錄中查找資源文件的類轉移到其他地方,它們將不再正常工作。如果有疑問,請不要使用此選項,以免影響包裝。

-keepattributes [attribute_filter]

指定保存所保存的參數名稱和方法類型。這個選項實際上保留了調試屬性LocalVariableTable和LocalVariableTypeTable的精簡版本。它在處理庫時非常有用。一些ide可以使用這些信息來幫助使用這個庫的開發(fā)人員,例如使用工具提示或自動完成。僅適用于開啟混淆。

-renamesourcefileattribute [string]

指定要放入類文件的SourceFile屬性(和SourceDir屬性)中的常量字符串。注意,屬性一開始就必須存在,因此還必須使用-keepattributes指令顯式地保存它。例如,您可能希望處理后的庫和應用程序生成有用的模糊堆棧跟蹤。僅適用于開啟混淆。

-adaptclassstrings [class_filter]

指定與類名對應的字符串常量也應該混淆。如果沒有過濾器,所有與類名對應的字符串常量都會被調整。對于篩選器,只有匹配篩選器的類中的字符串常量才會被調整。例如,如果您的代碼包含大量引用類的硬編碼字符串,并且您不希望保留它們的名稱,那么您可能希望使用這個選項。主要適用于混淆時,雖然相應的類也會自動保存在收縮步驟中。

-adaptresourcefilenames [file_filter]

根據相應類文件(如果有)的混淆名稱,指定要重命名的資源文件。如果沒有篩選器,與類文件對應的所有資源文件都將被重命名。使用篩選器,只重命名匹配的文件。例如,請參見處理資源文件。僅適用于開啟混淆。

-adaptresourcefilecontents [file_filter]

指定要更新其內容的資源文件。資源文件中提到的任何類名都將根據相應類(如果有的話)的混淆名稱進行重命名。如果沒有篩選器,則更新所有資源文件的內容。使用篩選器,只更新匹配的文件。資源文件使用平臺的默認字符集進行解析和編寫。您可以通過設置環(huán)境變量LANG或Java系統(tǒng)屬性file.encoding來更改這個默認字符集。例如,請參見處理資源文件。僅適用于開啟混淆。

預校驗 選項

-dontpreverify

指定不預驗證處理后的類文件。默認情況下,如果類文件的目標是Java微版本或Java 6或更高版本,則會預先驗證它們。對于Java微版本,需要預驗證,因此如果指定此選項,則需要對處理后的代碼運行外部預驗證器。對于Java 6,不需要(目前)預先驗證,但是它提高了Java虛擬機中類加載的效率。

-microedition

指定處理后的類文件以Java微版本為目標。然后,preverifier將添加適當的StackMap屬性,這與Java標準版的默認StackMapTable屬性不同。例如,如果您正在處理midlet,則需要此選項。

一般 可選項

-verbose

指定在處理過程中寫入更多信息。如果程序以異常終止,該選項將打印出整個堆棧跟蹤,而不僅僅是異常消息。

-dontnote [class_filter]

指定不打印有關配置中可能出現的錯誤或遺漏的注釋,如類名中的拼寫錯誤,或可能有用的選項缺失。可選過濾器是一個正則表達式;ProGuard不打印具有匹配名稱的類的注釋。

-dontwarn [class_filter]

指定根本不警告未解析的引用和其他重要問題??蛇x過濾器是一個正則表達式;ProGuard不會打印關于具有匹配名稱的類的警告。忽視警告是危險的。例如,如果處理確實需要未解析的類或類成員,那么處理后的代碼將不能正常工作。只有當你知道你在做什么時才使用這個選項!

-ignorewarnings

指定打印關于未解析引用和其他重要問題的警告,但在任何情況下都要繼續(xù)處理。忽視警告是危險的。例如,如果處理確實需要未解析的類或類成員,那么處理后的代碼將不能正常工作。只有當你知道你在做什么時才使用這個選項!

-printconfiguration [filename]

指定用包含的文件和替換的變量寫出已解析的整個配置。結構被打印到標準輸出或給定文件中。有時,這對于調試配置或將XML配置轉換為更具可讀性的格式非常有用。

-dump [filename]

指定在任何處理之后寫出類文件的內部結構。結構被打印到標準輸出或給定文件中。例如,您可能想要寫出給定jar文件的內容,而根本不需要處理它。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容