用ProGuard進(jìn)行代碼混淆技術(shù)詳解

目前項目android客戶端需要代碼混淆,抽空了解了下ProGuard的原理及使用,記錄下來以備后續(xù)使用。

目錄

ProGuard簡介
ProGuard使用原理
studio下編寫ProGuard文件

ProGuard簡介

ProGuard是一個集壓縮(Shrink)、混淆(Obfuscate)、優(yōu)化(Optimize)Java字節(jié)碼文件(.class)的免費工具,可以刪除多余的類、方法、無效的注釋,最大限度的優(yōu)化字節(jié)碼文件。上線的app反編譯后出現(xiàn)的命名都是通過ProGuard生成的,增加了反編譯的難度。
官網(wǎng)介紹:The ProGuard tool shrinks, optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and methods with semantically obscure names. The result is a smaller sized .apkfile that is more difficult to reverse engineer。

ProGuard使用原理

通過前面的介紹,我們知道了ProGuard技術(shù)是由Shrink、Optimize、Obfuscate,還有一個preverify(預(yù)檢)四個功能點組成,每個功能點都是可以選擇的。那么ProGuard是如何工作的呢?在這里我們引入一個概念EntryPoint。EntryPoint可以理解為一種標(biāo)志,它是在ProGuard過程中不會被處理的類或者方法,在壓縮的過程,ProGuard會從上述的EntryPoint中開始遍搜索出哪些類和類的成員在使用(被標(biāo)記為EntryPoint的類和方法有些是在使用的而且這些是我們在混淆文件中配置不希望被混淆的類和方法,有些是沒有使用的)。
對于那些沒有被使用的類和成員,就會在壓縮階段被丟棄。然后在接下來的優(yōu)化步驟中,那些非EntryPoint的類,方法都會被設(shè)置為private,static或者final,而且不使用的參數(shù)都會被移除。接著在混淆的步驟中,ProGuard會對非EntryPoint的類和方法進(jìn)行重命名。最后就會對代碼進(jìn)行預(yù)檢測,以便保證穩(wěn)定性。

studio下編寫ProGuard文件

studio下可以通過build.gradle進(jìn)行Proguard的相關(guān)配置:
release {
minifyEnabled true // 是否進(jìn)行代碼混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// proguard-androi.txt是android默認(rèn)的混淆聲明,proguard-rules.pro為自定義的混淆申明
}
如下是在網(wǎng)上找到的一份模板,比較完善:

# 代碼混淆壓縮比,在0~7之間,默認(rèn)為5,一般不做修改
-optimizationpasses 5

#  混合時不使用大小寫混合,混合后的類名為小寫
-dontusemixedcaseclassnames

#  指定不去忽略非公共庫的類
-dontskipnonpubliclibraryclasses

# 這句話能夠使我們的項目混淆后產(chǎn)生映射文件
# 包含有類名->混淆后類名的映射關(guān)系
-verbose

#  指定不去忽略非公共庫的類成員
-dontskipnonpubliclibraryclassmembers

#  不做預(yù)校驗,preverify是proguard的四個步驟之一,Android不需要preverify,去掉這一步能夠加快混淆速度。
-dontpreverify

#  保留Annotation不混淆
-keepattributes *Annotation*,InnerClasses

#  避免混淆泛型
-keepattributes Signature

#  拋出異常時保留代碼行號
-keepattributes SourceFile,LineNumberTable

#  指定混淆是采用的算法,后面的參數(shù)是一個過濾器這個過濾器是谷歌推薦的算法,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*


#############################################
#
#  Android開發(fā)中一些需要保留的公共部分
#
#############################################

#  保留我們使用的四大組件,自定義的Application等等這些類不被混淆
#  因為這些子類都有可能被外部調(diào)用
-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.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService


#  保留support下的所有類及其內(nèi)部類
-keep class 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$* {*;}

#  保留本地native方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}

#  保留在Activity中的方法參數(shù)是view的方法,這樣以來我們在layout中寫的onClick就不會被影響
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}

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

#  保留我們自定義控件(繼承自View)不被混淆
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

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

#######  保留Serializable序列化的類不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    !private <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

#  對于帶有回調(diào)函數(shù)的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
    void *(**On*Event);
    void *(**On*Listener);
}

#  webView處理,項目中沒有使用到webView忽略即可
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
    public *;
}
-keepclassmembers class * extends android.webkit.webViewClient {
    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
    public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.webViewClient {
    public void *(android.webkit.webView, jav.lang.String);
}

#############################################
#
#  項目中特殊處理部分
#
#############################################

#-----------處理反射類---------------

# -----------處理js交互---------------

# -----------處理實體類---------------
-keep class x.x.*{*;}


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

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,781評論 25 709
  • Android插件化基礎(chǔ)的主要內(nèi)容包括 Android插件化基礎(chǔ)1-----加載SD上APKAndroid插件化基...
    隔壁老李頭閱讀 7,388評論 13 48
  • 混淆(Proguard)用法 最近項目中遇到一些混淆相關(guān)的問題,由于之前對proguard了解不多,所以每次都是面...
    于曉飛93閱讀 57,153評論 38 230
  • 聲明 這篇文章更多的是做一個整理,內(nèi)容來自于ProGuard官方文檔以及各種博客等,相關(guān)文章的鏈接在參考目錄里,感...
    夷陵小祖閱讀 3,793評論 0 23
  • 這一年經(jīng)歷了很多事情,雖然有時覺得很痛苦,回頭細(xì)想其實很感謝生活無數(shù)次給予我的點醒,點醒我別再活的那么擰巴...
    雨嫣然閱讀 200評論 0 0

友情鏈接更多精彩內(nèi)容