目前項目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的類和方法進行重命名。最后就會對代碼進行預(yù)檢測,以便保證穩(wěn)定性虐杯。
studio下編寫ProGuard文件
studio下可以通過build.gradle進行Proguard的相關(guān)配置:
release {
minifyEnabled true // 是否進行代碼混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// proguard-androi.txt是android默認的混淆聲明玛歌,proguard-rules.pro為自定義的混淆申明
}
如下是在網(wǎng)上找到的一份模板,比較完善:
# 代碼混淆壓縮比擎椰,在0~7之間支子,默認為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.*{*;}
# -----------處理第三方依賴庫---------