Android中的Proguard使用

介紹

之前介紹瞭如何使用命令行將Jar包根據配置文件進行ProGuard,以及ProGuard的過程,會遇到的問題等。接下來會介紹常用的ProGuard如何配置參數。不常用的可以在官網中查詢如何使用。

java -jar proguard.jar @myconfig.pro

Filter

每一個類、屬性、方法都會有一個全名,例如java.lang.String。而我們也可以通過正則表達式來過濾我們所需要的名稱。

  • ?:在class中匹配任意的單個字符 例如:mypackage.Test?可以匹配mypackage.Test1mypackage.Test2,但是不能匹配mypackage.Test12
  • *:匹配任意class名稱中的一部分 例如:mypackage.*Test*可以匹配mypackage.Test,也可以匹配mypackage.YouTestApplication,但是不能匹配mypackage.subpackage.MyTest
  • **:可以匹配class名稱中的任意一部分,可以包括任何數字或者包分隔符。 例如:**.Test可以匹配除了根目錄下所有包名下的Test類。mypackage.**則可以匹配所有在mypackage和它子目錄的所有類

而Fields和Methods與Java中類似。除了Method的參數中不需要包含它的名字,就和Javap中一樣。而匹配規則如下:

  • <init>:匹配任意構造函數 -<fields>:匹配任意屬性 -<methods>:匹配任意函數 -*:匹配任意屬性或者函數

Input / Output Options

  • @filename 這種方式,是-include filename的縮寫,該選項的作用是遞歸讀取所給文件中的屬性
  • -basedirectory directoryPath 指定配置文件的目錄
  • -injars class_path 指定輸入Jar包的路徑,可以指定多個路徑,而輸入的Entity可以被過濾
  • -outjars class_path 指定輸出Jar包路徑,同上而輸出的Entity可以被過濾
  • libraryjars class_path 指定要被處理的Jar包。這些文件不會被打包到output jar包中。指定的Library應該至少包含一個Class文件被Application Class文件中使用extended繼承了。
  • -skipnonpubliclibraryclasses 當讀取library的時候,跳過non-public的類,以提升處理速度並且減少ProGuard內存佔用。默認ProGuard會讀取public以及non-public的類。然而,non-public的類通常沒有關聯的。可以忽略他們,提升ProGuard速度,而且也不會影響output。但是有一些lib,例如JSE run-time,包含了non-public的類,但是它還可以被public的library繼承。所以你不能使用這個option。如果因爲這個option無法找到那個class的話 ,ProGuard會打印出來Warning的。
  • -dontskipnonpubliclibraryclasses 從4.5版本開始,默認就指定了該屬性。該屬性制定了不要忽略non-public的類
  • -dontskipnonpubliclibraryclassmembers 指定不要忽略package visible的類成員(Field以及Method)。默認的,ProGuard在解析classes會跳過這些類成員,因爲程序通常不會引用它們。有些情況下,程序的包和Library的包相同,從而可以引用包可見的類成員。在這種情況下,實際讀取類成員是有用的,以確保處理後的代碼保持一致。
  • keepdirectories directory_filter 指定輸出路徑中需要Keep的目錄。默認情況下,目錄的Entries會被移除掉,用來減少Jar包的大小。但是有可能程序會有MyClass.class.getResource("")這種代碼出現,如果沒有指定一個Directory Filter的話,那麼所有的目錄都會被Keep住。如果有Filter的話,則會Keep匹配目錄。

Keep Options

  • -keep: Keep住所有繼承自Activity、Application的類
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider

Keep住所有繼承自View類中的public構造函數以及所有以public void set開始的函數。

-keep public class * extends android.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}
  • -keepclassmembers Keep住類中的成員。
-keepclassmembers class * implements java.io.Serializable {
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
-keepclassmembers class * implements android.os.Parcelable {
    static android.os.Parcelable$Creator CREATOR;
}
-keepclassmembers class **.R$* {
    public static <fields>;
}
  • -keepclasseswithmembers Keep住能匹配到規則的類。如下,會Keep住所有構造函數帶有Context、AttributeSet的類。
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
  • -keepclassmembernames Keep住類成員。如果它們沒有在Shrink階段被移除的話
-keepclassmembernames class scala.concurrent.forkjoin.ForkJoinPool {
    long eventCount;
    int  workerCounts;
    int  runControl;
    scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode syncStack;
    scala.concurrent.forkjoin.ForkJoinPool$WaitQueueNode spareStack;
}
  • -keepclasseswithmembernames 根據類成員名稱來Keep住類。如下,如果有Native函數的類全部都會被Keep住
-keepclasseswithmembernames class * {
    native <methods>;
}

參考資料

ProGuard的使用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章