ProGuard介紹 ProGuard是一個Java類文件壓縮器,優化器,混淆器和預先文件驗證器。 壓縮步驟檢測和刪除未使用的類,欄位,方法和屬性。 優化步驟分析和優化方法的位元組碼。 混淆步驟使用短無意義的名稱重命名剩餘的類,欄位和方法。 這些步驟使代碼更小,更高效,更難以進行逆向工程。 最終的預驗 ...
ProGuard介紹
ProGuard是一個Java類文件壓縮器,優化器,混淆器和預先文件驗證器。 壓縮步驟檢測和刪除未使用的類,欄位,方法和屬性。 優化步驟分析和優化方法的位元組碼。 混淆步驟使用短無意義的名稱重命名剩餘的類,欄位和方法。 這些步驟使代碼更小,更高效,更難以進行逆向工程。 最終的預驗證步驟將預驗證信息添加到類,這是Java Micro Edition和Java 6及更高版本所必需的。
所以我們可以通過開啟 ProGuard 來去除未使用的類、欄位、方法和屬性,包括自帶代碼庫中的未使用項,這樣就以變通方式解決了 64k 限制的問題。同時ProGuard 還可優化位元組碼,移除未使用的代碼指令,以及用短名稱混淆其餘的類、欄位和方法。這樣也在一定程度上減少了Apk的大小。
ShrinkResources資源壓縮通過 Android Plugin for Gradle 提供,該插件會移除應用中未使用的資源,包括庫中未使用的資源。同樣也可減少Apk的大小。
如何啟用壓縮和混淆?
先上代碼,在build.gradle中配置如下:
android { buildTypes { release { minifyEnabled true //啟用代碼壓縮 shrinkResources true //啟用資源壓縮 proguardFiles getDefaultProguardFile(‘proguard-android.txt'), 'proguard-rules.pro'//混淆規則文件配置 } } }
- getDefaultProguardFile(‘proguard-android.txt’)
這個配置的意思是從 Android SDK tools/proguard/ 文件夾獲取預設 ProGuard 設置。使用 proguard-android-optimize.txt 可以進一步的壓縮代碼還包括其他在位元組碼一級(方法內和方法間)執行分析的優化,可進一步減小 APK 大小和幫助提高其運行速度。 - proguard-rules.pro
可以在這個文件中添加自定義的規則,該文件和build.gradle在同級目錄下。
ProGuard的輸出文件及用處:
混淆過程完成後會生成如下幾個文件,
dump.txt
說明 APK 中所有類文件的內部結構。
mapping.txt
提供原始與混淆過的類、方法和欄位名稱之間的轉換。
seeds.txt
列出未進行混淆的類和成員。
usage.txt
列出從 APK 移除的代碼。
這些文件保存在 /build/outputs/mapping/release/目錄下。
這裡需要特別註意:每次release新版編譯後,最好將這些文件加入git版本庫一起保存,因為每次Release編譯後這些文件都會被覆蓋。
ProGuard配置說明
保留配置(即對配置的內容不進行處理)
-keep [,modifier,…] class_specification
指定要保留的類和類成員(欄位和方法)。
-keepclassmembers [,modifier,…] class_specification
指定要保留的類成員,如果它們的類也被保留。 例如,你可能希望保留實現Serializable介面的所有序列化欄位和類的方法。
-keepclasseswithmembers [,modifier,…] class_specification
指定要保留的類和類成員,條件是所有指定的類成員都存在。 例如,你可能希望保留所有具有main方法的應用程式,而無需顯式列出。
-keepnames class_specification
-keep的縮寫,允許class_specification
指定要保存的類和類成員的名稱(如果它們在壓縮階段不被刪除)。 例如,你可能希望保留實現Serializable介面的類的所有類名,以便處理的代碼與任何原始的序列化類保持相容。 根本不使用的類仍然可以刪除。 只適用於混淆。
-keepclassmembernames class_specification
–keepclassmembers的縮寫,allowhrinking class_specification
指定要保存其名稱的類成員,如果它們在壓縮階段未被刪除。 例如,當處理由JDK 1.2或更舊版本編譯的庫時,你可能希望保留內部類$ 方法的名稱,因此當處理使用已處理庫的應用程式時,混淆器可以再次檢測它(儘管ProGuard本身不需要 這個)。 只適用於混淆。
-keepclasseswithmembernames class_specification
–keepclasseswithmembernames的縮寫,允許class_specification
指定要保留其名稱的類和類成員,條件是所有指定的類成員在收縮階段之後都存在。 例如,你可能希望保留所有本機方法名稱和其類的名稱,以便處理後的代碼仍然可以鏈接到本機庫代碼。 根本不使用的本地方法仍然可以刪除。 如果使用一個類文件,但是它的本機方法都不是,它的名字仍然會被模糊。 只適用於混淆。
-printseeds [filename]
指定徹底列出由各種保護選項匹配的類和類成員。 列表列印到標準輸出或給定文件。 該列表可用於驗證是否真正找到預期的類成員,特別是如果你使用通配符。 例如,你可能希望列出所有應用程式或所有保留的小程式。
壓縮
-dontshrink
指定不壓縮的類文件。
-printusage {filename}
指定需要列出dead code的類文件。 可以列出應用程式的未使用的代碼。 只適用於壓縮。
-whyareyoukeeping {class_specification}
指定列印關於給定類和類成員在壓縮步驟中keep的原因的詳細信息。 只適用於壓縮。
優化
-dontoptimize
指定不優化輸入類文件。 預設情況下,啟用優化; 所有方法都以位元組碼級別進行了優化。
-optimizations optimization_filter
指定要在更細粒度的級別啟用和禁用的優化。 僅適用於優化。 這是一個專家選項。
-optimizationpasses n
指定要執行的優化通過次數。 預設情況下,執行單程。 多次通過可能會導致進一步的改進。 如果在優化通過後沒有找到改進,則優化結束。 僅適用於優化。
-assumenosideeffects class_specification
指定沒有任何副作用的方法(可能返回值除外)。 在優化步驟中,ProGuard會刪除對這些方法的調用,如果可以確定不使用返回值。例如,你可以指定方法System.out(),以便 用該選項來刪除日誌記錄代碼。 註意,該選項 僅適用於優化。 除非你很清楚這個方法的作用,否則請勿使用這個選項!
-allowaccessmodification
指定在處理過程中可以擴展類和類成員的訪問修飾符。 這可以改善優化步驟的結果。
-mergeinterfacesaggressively
指定介面可能被合併,即使它們的實現類不實現所有介面方法。 這可以通過減少類的總數來減少輸出的大小。
混淆
-dontobfuscate 不混淆輸入的類文件
-obfuscationdictionary {filename} 使用給定文件中的關鍵字作為要混淆方法的名稱
-overloadaggressively 混淆時應用侵入式重載
-useuniqueclassmembernames 確定統一的混淆類的成員名稱來增加混淆
-flattenpackagehierarchy {package_name} 重新包裝所有重命名的包並放在給定的單一包中
-repackageclass {package_name} 重新包裝所有重命名的類文件中放在給定的單一包中
-dontusemixedcaseclassnames 混淆時不會產生形形色色的類名
-keepattributes {attribute_name,…} 保護給定的可選屬性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-renamesourcefileattribute {string} 設置源文件中給定的字元串常量
在配置過程中可以使用通配符,關於通配符的說明如下,
通配符 | 說明 |
---|---|
? | 匹配任何單字元。 |
* | 匹配除了包分隔符或目錄分隔符之外的任何字元。 |
** | 匹配任何字元的名稱 |
自定義要保留的代碼
通常來說,預設 ProGuard 配置文件 (proguard-android.txt) 足以滿足需要,ProGuard 會移除所有(並且只會移除)未使用的代碼。但是對許多情況進行正確分析時,可能會移除有用的代碼。
以下幾種情況下它可能錯誤移除有用代碼:
- 當應用引用的類只來自 AndroidManifest.xml 文件時
- 當應用調用的方法來自 Java 原生介面 (JNI) 時
- 當應用在運行時(例如使用反射或自檢)操作代碼時
- 當使用Parcelable的子類和Creator靜態成員變數時
- 當使用GSON、fastjson等框架時,所寫的JSON對象類如果進行混淆會造成無法將JSON解析成對應的對象
- 當使用第三方開源庫或者引用其他第三方的SDK包時
- 當有用到WEBView的JS調用時
在進行應用測試時應該能夠發現這些因不當移除而導致的錯誤,具體也可查看 usage.txt 的內容來檢查移除了哪些代碼。
例如類似下麵這樣的錯誤,我們就需要配置keep這些類不被混淆
10:47:34.635 [ERROR] [system.err] Warning: com.kennyc.view.MultiStateView$1: can't find referenced method 'com.kennyc.view.MultiStateView$ViewState[] values()' in program class com.kennyc.view.MultiStateView$ViewState 10:47:34.636 [ERROR] [system.err] Warning: com.kennyc.view.MultiStateView$1: can't find referenced field 'com.kennyc.view.MultiStateView$ViewState LOADING' in program class com.kennyc.view.MultiStateView$ViewState
配置內容如下即可解決問題:
-keep class com.kennyc.**
在AndroidMainfest中的類不會混淆,四大組件和Application的子類和Framework層下所有的類預設不會進行混淆,android提供的預設配置中都有。以下就是Android SDK中預設的ProGuard配置,即proguard-android.txt的內容
# This is a configuration file for ProGuard. # http://proguard.sourceforge.net/index.html#manual/usage.html -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -verbose # Optimization is turned off by default. Dex does not like code run # through the ProGuard optimize and preverify steps (and performs some # of these optimizations on its own). -dontoptimize -dontpreverify # Note that if you want to enable optimization, you cannot just # include optimization flags in your own project configuration file; # instead you will need to point to the # "proguard-android-optimize.txt" file instead of this one from your # project.properties file. -keepattributes *Annotation* -keep public class com.google.vending.licensing.ILicensingService -keep public class com.android.vending.licensing.ILicensingService # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native -keepclasseswithmembernames class * { native <methods>; } # keep setters in Views so that animations can still work. # see http://proguard.sourceforge.net/manual/examples.html#beans -keepclassmembers public class * extends android.view.View { void set*(***); *** get*(); } # We want to keep methods in Activity that could be used in the XML attribute onClick -keepclassmembers class * extends android.app.Activity { public void *(android.view.View); } # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keepclassmembers class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator CREATOR; } -keepclassmembers class **.R$* { public static <fields>; } # The support library contains references to newer platform versions. # Don't warn about those in case this app is linking against an older # platform version. We know about them, and they are safe. -dontwarn android.support.** # Understand the @Keep support annotation. -keep class android.support.annotation.Keep -keep @android.support.annotation.Keep class * {*;} -keepclasseswithmembers class * { @android.support.annotation.Keep <methods>; } -keepclasseswithmembers class * { @android.support.annotation.Keep <fields>; } -keepclasseswithmembers class * { @android.support.annotation.Keep <init>(...); }
列舉一些庫的混淆配置
##---------------Begin: proguard configuration for Twitter ---------- -dontwarn com.squareup.okhttp.** -dontwarn com.google.appengine.api.urlfetch.** -dontwarn rx.** -dontwarn retrofit.** -keepattributes Signature -keepattributes *Annotation* -keep class com.squareup.okhttp.** { *; } -keep interface com.squareup.okhttp.** { *; } -keep class retrofit.** { *; } -keepclasseswithmembers class * { @retrofit.http.* <methods>; } ##---------------End: proguard configuration for Twitter ----------
##---------------Begin: proguard configuration for Gson ---------- # Gson uses generic type information stored in a class file when working with fields. Proguard # removes such information by default, so configure it to keep all of it. -keepattributes Signature # For using GSON @Expose annotation -keepattributes *Annotation* # Gson specific classes -keep class sun.misc.Unsafe { *; } #-keep class com.google.gson.stream.** { *; } # Application classes that will be serialized/deserialized over Gson -keep class com.google.gson.examples.android.model.** { *; } # Prevent proguard from stripping interface information from TypeAdapterFactory, # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) -keep class * implements com.google.gson.TypeAdapterFactory -keep class * implements com.google.gson.JsonSerializer -keep class * implements com.google.gson.JsonDeserializer ##---------------End: proguard configuration for Gson ----------
##---------------Begin: proguard configuration for Glide ---------- -keep public class * implements com.bumptech.glide.module.GlideModule -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { **[] $VALUES; public *; } ##---------------End: proguard configuration for Glide ----------
##---------------Begin: proguard configuration for EventBus ---------- -keepattributes *Annotation* -keepclassmembers class ** { @org.greenrobot.eventbus.Subscribe <methods>; } -keep enum org.greenrobot.eventbus.ThreadMode { *; } # Only required if you use AsyncExecutor #-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { # <init>(java.lang.Throwable); #} ##---------------End: proguard configuration for EventBus ----------
##---------------Begin: proguard configuration for Paper ---------- #1.Keep data classes: -keep class com.bloomsky.android.model.** { *; } #2.alternatively you can implement Serializable for all your data classes and keep all of them using: #-keep class * implements java.io.Serializable { *; } ##---------------End: proguard configuration for Paper ----------
##---------------Begin: proguard configuration for retrofit2 ---------- # Platform calls Class.forName on types which do not exist on Android to determine platform. -dontnote retrofit2.Platform # Platform used when running on Java 8 VMs. Will not be used at runtime. -dontwarn retrofit2.Platform$Java8 # Retain generic type information for use by reflection by converters and adapters. -keepattributes Signature # Retain declared checked exceptions for use by a Proxy instance. -keepattributes Exceptions ##---------------End: proguard configuration for retrofit2 ----------
移除調試log代碼的配置
移除Log類列印各個等級日誌的代碼,打正式包的時候可以做為禁log使用,這裡可以作為禁止log列印的功能使用,另外的一種實現方案是通過BuildConfig.DEBUG的變數來控制
-assumenosideeffects class android.util.Log { public static *** v(...); public static *** i(...); public static *** d(...); public static *** w(...); public static *** e(...); }
恢復混淆前的堆棧信息
當混淆後的代碼輸出一個堆棧信息時,方法名是不可識別的,這使得調試變得很困難,甚至是不可能的。幸運的是,當ProGuard運行時,它都會輸出一個/build/outputs/mapping/release/mapping.txt文件,而這個文件中包含了原始的類,方法和欄位名被映射成的混淆名字。
retrace.bat腳本(Window)或retrace.sh腳本(Linux,Mac OS X)可以將一個被混淆過的堆棧跟蹤信息還原成一個可讀的信息。它位於/tools/proguard文件夾中。執行retrace工具的語法如下:
retrace.bat|retrace.sh [-verbose] mapping.txt []
例如:
./retrace.sh -verbose mapping.txt obfuscated_trace.txt
如果你沒有指定,retrace工具會從標準輸入讀取。
原文地址:http://blog.csdn.net/ocean20/article/details/67634130
更多關於ProGuard的信息可以訪問,
https://www.guardsquare.com/en/proguard/manual/examples