Android ProGuard混淆總結

目錄
一、前言
二、ProGuard簡介
三、ProGuard原理分析
四、ProGuard注意事項
五、Android中的混淆
Android開啓混淆的設置
ProGuard基本命令
Android混淆方案實例

參考

一、前言

  • 編譯型語言:程序在執行之前需要一個專門的編譯過程,把程序編譯成機器語言的文件,運行時不需要重新翻譯,直接使用編譯的結果就行了。程序執行效率高,依賴編譯器,跨平臺性差些。C、C++、Delphi、Pascal、Fortran

  • 解釋型語言:不需要在運行前編譯,在運行程序的時候才翻譯,專門的解釋器負責在每個語句執行的時候解釋程序代碼。這樣解釋型語言每執行一次就要翻譯一次,效率比較低。Java、Basic、javascript、python

java文件先編譯成與平臺無關的.class的字節碼文件,然後.class文件在java虛擬機(JVM)上進行解釋運行。由於跨平臺的特性,Java字節碼中包含許多源代碼信息,如變量名、方法名,並且通過這些名稱來訪問變量和方法。這些信息很容易被反編譯成Java源代碼,所以我們使用混淆器對Java字節碼進行混淆。

使用混淆的原因:

  1. 混淆後的代碼很難被反編譯,即使被反編譯了也很難看懂真正語義。
  2. 混淆後的代碼保留原來的檔案格式和指令集,執行結果與混淆前一樣。

二、ProGuard簡介

ProGuard是一個壓縮、優化和混淆Java字節碼文件的免費的工具,它可以刪除無用的類、字段、方法和屬性。可以刪除沒用的註釋,最大限度地優化字節碼文件。它還可以使用簡短的無意義的名稱來重命名已經存在的類、字段、方法和屬性。常常用於Android開發用於混淆最終的項目,增加項目被反編譯的難度。__來自百度百科

ProGuard的四個功能:

  1. 壓縮(Shrink):檢測並移除代碼中無用的類、字段、方法和特性(Attribute)。
  2. 優化(Optimize):對字節碼進行優化,移除無用的指令。
  3. 混淆(Obfuscate):使用a,b,c,d這樣簡短而無意義的名稱,對類、字段和方法進行重命名。
  4. 預檢(Preveirfy):在Java平臺上對處理後的代碼進行預檢,確保加載的class文件是可執行的。

三、ProGuard原理分析

編譯過程圖來自ProGuard官網。Entry Point是在ProGuard過程中不會被處理的類或方法。在壓縮的步驟中,ProGuard會從上述的Entry Point開始遞歸遍歷,搜索哪些類和類的成員在使用,對於沒有被使用的類和類的成員,就會在壓縮段丟棄,在接下來的優化過程中,那些非Entry Point的類、方法都會被設置爲private、static或final,不使用的參數會被移除,此外,有些方法會被標記爲內聯的,在混淆的步驟中,ProGuard會對非Entry Point的類和方法進行重命名。
編譯過程圖

四、ProGuard注意事項

不能混淆的情況:

  1. Java的反射:代碼混淆,類名、方法名、屬性名都改變了,而反射是按照原來的名字去反射,所以會反射錯誤。
  2. 註解:註解用了反射,所以不能混淆。
  3. native:不混淆任何包含native方法的類的類名以及native方法名,否則找不到本地方法。
  4. Activity:Activity不能混淆,因爲AndroidManifest.xml文件中是完整的名字。
  5. 自定義view:自定義view也是帶了包名寫在xml佈局中,不能混淆。

五、Android中的混淆

Android開啓混淆的設置

app混淆的開啓:

android{
	buildTypes {
	        release {
	            minifyEnabled true   //開啓混淆
	            zipAlignEnabled true  //壓縮優化
	            shrinkResources true  //移出無用資源
	            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
	            signingConfig signingConfigs.config
	            }
	        }
}

module混淆的開啓(子模塊是否混淆受app的build.gradle的控制;子模塊混淆使用consumerProguardFiles關鍵字):

android{
	buildTypes {
	        release {
	            consumerProguardFiles 'proguard-rules.pro'
	            }
	        }
}

ProGuard基本命令

通配符      描述
<field>     匹配類中的所有字段
<method>    匹配類中所有的方法
<init>      匹配類中所有的構造函數
*           匹配任意長度字符,不包含包名分隔符(.)
**          匹配任意長度字符,包含包名分隔符(.)
***         匹配任意參數類型

系統配置:

  • dontusemixedcaseclassnames 混淆時不使用大小寫混合類名
  • dontskipnonpubliclibraryclasses 不跳過library中的非public的類
  • verbose 打印混淆的詳細信息
  • dontoptimize 不進行優化,建議使用此選項,
  • dontpreverify 不進行預校驗,Android不需要,可加快混淆速度。
  • ignorewarnings 忽略警告
  • optimizationpasses 5 指定代碼的壓縮級別

保留選項:

  • keep{Modifier}{class_specification}: 保護指定的類文件(類名)和類成員, 防止被混淆或移除
  • keepclassmembers{Modifier}{class_specification}: 通過成員來指定來只保護指定類的某些成員, 防止被混淆或移除, 注意類名還是會被混淆
  • keepclasswithmembers{class_specification}: 通過成員來指定哪些類不被混淆處理。保持匹配到的類的類名和指定的方法不被混淆,其他未指定的方法仍然會被混淆
  • keepnames{class_specification}: 等於-keep,allowshrinking class_specification的別名,允許該類被壓縮,未被使用的元素將會在壓縮階段被移除,此選項會保持對應的類名和指定的成員不被混淆(未指定的成員依然會被混淆)
  • keepclassmembernames{class_specification}: -keepclasseswithmembers,allowshrinking class_specification的別名,但是未使用的類和成員可能會在壓縮階段被移除
  • keepclasseswithmembernames {class_specification}: -keepclasseswithmembers,allowshrinking class_specification的別名,未使用的類和成員可能會在壓縮階段被移除

壓縮:

  • dontshrink: 不壓縮輸入的類文件
  • printusage{filename}: 輸出無用文件

優化:

  • dontoptimize: 不優化輸入的類文件
  • assumenosideeffects{class_specification}: 在優化階段移除相關方法的調用
  • allowaccessmodification: 優化時允許訪問並修改有修飾符的類和類成員變量

混淆:

  • dontobfuscate不混淆輸入的類文件
  • printmapping proguardMapping.txt : 輸出映射表
  • applymapping{filename}:重用映射增加混淆。
  • obfuscationdictionary{filename}: 使用給的文件中的關鍵作爲要混淆方法的名稱。
  • overloadaggressively:混淆時應用侵入式重載。混淆的時候大量使用重載,多個方法名使用同一個混淆名(慎用)
  • useuniqueclassmembernames:確定統一的混淆類的成員名稱來增加混淆。
  • renamesourcefileattribute{string}:設置源文件中給定的字符串常量。

預檢:

  • dontpreverify

Android混淆方案實例

# 代碼混淆壓縮比,在0~7之間
-optimizationpasses 5
# 混合時不使用大小寫混合,混合後的類名爲小寫
-dontusemixedcaseclassnames
# 指定不去忽略非公共庫的類
-dontskipnonpubliclibraryclasses
# 不做預校驗,preverify是proguard的四個步驟之一,Android不需要preverify,去掉這一步能夠加快混淆速度。
-dontpreverify
-verbose
# 避免混淆泛型
-keepattributes Signature

#保留Annotation不混淆
-keepattributes *Annotation*,InnerClasses
#google推薦算法
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
# 避免混淆Annotation、內部類、泛型、匿名類
-keepattributes *Annotation*,InnerClasses,Signature,EnclosingMethod
# 重命名拋出異常時的文件名稱
-renamesourcefileattribute SourceFile
# 拋出異常時保留代碼行號
-keepattributes SourceFile,LineNumberTable
# 處理support包
-dontnote android.support.**
-dontwarn android.support.**
# 保留繼承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**

# 保留R下面的資源
-keep class **.R$* {*;}
# 保留四大組件,自定義的Application等這些類不被混淆
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Appliction
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService

# 保留在Activity中的方法參數是view的方法,
# 這樣以來我們在layout中寫的onClick就不會被影響
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
# 對於帶有回調函數的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
    void *(**On*Event);
    void *(**On*Listener);
}
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}

# 保留枚舉類不被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# 保留Parcelable序列化類不被混淆
-keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}

-keepclassmembers class * implements java.io.Serializable {
   static final long serialVersionUID;
   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();
}
#assume no side effects:刪除android.util.Log輸出的日誌
-assumenosideeffects class android.util.Log {
    public static *** v(...);
    public static *** d(...);
    public static *** i(...);
    public static *** w(...);
    public static *** e(...);
}
#保留Keep註解的類名和方法
-keep,allowobfuscation @interface android.support.annotation.Keep
-keep @android.support.annotation.Keep class *
-keepclassmembers class * {
    @android.support.annotation.Keep *;
}
#3D 地圖 V5.0.0之前:

-dontwarn com.amap.api.**
-dontwarn com.autonavi.**
-keep class com.amap.api.**{*;}
-keep class com.autonavi.**{*;}

-keep   class com.amap.api.maps.**{*;}
-keep   class com.autonavi.amap.mapcore.*{*;}
-keep   class com.amap.api.trace.**{*;}

#3D 地圖 V5.0.0之後:
-keep   class com.amap.api.maps.**{*;}
-keep   class com.autonavi.**{*;}
-keep   class com.amap.api.trace.**{*;}

#定位
-keep class com.amap.api.location.**{*;}
-keep class com.amap.api.fence.**{*;}
-keep class com.autonavi.aps.amapapi.model.**{*;}

#搜索
-keep   class com.amap.api.services.**{*;}

#2D地圖
-keep class com.amap.api.maps2d.**{*;}
-keep class com.amap.api.mapcore2d.**{*;}

#導航
-keep class com.amap.api.navi.**{*;}
-keep class com.autonavi.**{*;}
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature

# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}

# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**

# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**

# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase

# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*

# OkHttp platform used only on JVM and when Conscrypt dependency is available.
-dontwarn okhttp3.internal.platform.ConscryptPlatform

#fastjson混淆
-keepattributes Signature
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.**{*;}
-keep class com.alibaba.fastjson.**{*; }
-keep public class com.ninstarscf.ld.model.entity.**{*;}

參考:

[https://www.jianshu.com/p/6408fbc3adca ](https://www.jianshu.com/p/6408fbc3adca ) [https://www.jianshu.com/p/e9d3c57ab92f](https://www.jianshu.com/p/e9d3c57ab92f)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章