代碼混淆(Obfuscated code)亦稱花指令府框,是將計算機程序的代碼主经,轉(zhuǎn)換成一種功能上等價偏竟,但是難于閱讀和理解的形式的行為硬纤。(混淆就是對發(fā)布出去的程序進行重新組織和處理,使得處理后的代碼與處理前代碼完成相同的功能咱士,而混淆后的代碼很難被反編譯立由,即使反編譯成功也很難得出程序的真正語義)
為什么要加代碼混淆?
1.保護代碼
2.精簡編譯后程序大小(混淆器將代碼中的所有變量、函數(shù)序厉、類的名稱變?yōu)楹喍痰挠⑽淖帜复?
開啟混淆
通常我們需要找到項目路徑下app目錄下的build.gradle文件
找到minifyEnabled這個配置,然后設置為true即可.
proguard-rules.pro
里面定義了我們的混淆規(guī)則
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
Proguard關鍵字
關鍵字 描述
-dontwarn dontwarn是一個和keep可以說是形影不離,尤其是處理引入的library時.
-keep 保留類和類中的成員锐膜,防止被混淆或移除
-keepnames 保留類和類中的成員,防止被混淆弛房,成員沒有被引用會被移除
-keepclassmembers 只保留類中的成員道盏,防止被混淆或移除
-keepclassmembernames 只保留類中的成員,防止被混淆文捶,成員沒有引用會被移除
-keepclasseswithmembers 保留類和類中的成員荷逞,防止被混淆或移除,保留指明的成員
-keepclasseswithmembernames 保留類和類中的成員粹排,防止被混淆种远,保留指明的成員,成員沒有引用會被移除
-keepattributes 保留某些屬性不被混淆顽耳,可選(*Annotation*,InnerClasses坠敷,Signature,SourceFile,LineNumberTable)
-keep
Proguard通配符
通配符 描述
<field> 匹配類中的所有字段
<method> 匹配類中所有的方法
<init> 匹配類中所有的構造函數(shù)
* 匹配任意長度字符斧抱,不包含包名分隔符(.)
** 匹配任意長度字符常拓,包含包名分隔符(.)
*** 匹配任意參數(shù)類型
引入的library可能存在一些無法找到的引用和其他問題,在build時可能會發(fā)出警告,如果我們不進行處理,通常會導致build中止.因此為了保證build繼續(xù),我們需要使用dontwarn處理這些我們無法解決的library的警告
-dontwarn com.mob.**
引入的library保留其包下面的類以及子包
-keep class com.mob.**{*;}
通常引入的library渐溶,如下配置
-keep class com.mob.**{*;}
-dontwarn com.mob.**
哪些不應該混淆
- 使用了自定義控件那么要保證它們不參與混淆
- 使用了枚舉要保證枚舉不被混淆
- 對第三方庫中的類不進行混淆
- 運用了反射的類也不進行混淆
- 使用了 Gson 之類的工具要使 JavaBean 類即實體類不被混淆
- 在引用第三方庫的時候辉浦,一般會標明庫的混淆規(guī)則的,建議在使用的時候就把混淆規(guī)則添加上去茎辐,免得到最后才去找
- 有用到 WebView 的 JS 調(diào)用也需要保證寫的接口方法不混淆宪郊,原因和第一條一樣
- Parcelable 的子類和 Creator 靜態(tài)成員變量不混淆掂恕,否則會產(chǎn)生Android.os.BadParcelableException 異常
- 使用的四大組件,自定義的Application* 實體類
- JNI中調(diào)用的類
- Layout布局使用的View構造函數(shù)(自定義控件)弛槐、android:onClick等懊亡。
模板
#############################################
#
# -基本不用動區(qū)域
#
#############################################
# 指定代碼的壓縮級別 0 - 7(指定代碼進行迭代優(yōu)化的次數(shù),在Android里面默認是5乎串,這條指令也只有在可以優(yōu)化時起作用店枣。)
-optimizationpasses 5
# 混淆時不會產(chǎn)生形形色色的類名(混淆時不使用大小寫混合類名)
-dontusemixedcaseclassnames
# 指定不去忽略非公共的庫類(不跳過library中的非public的類)
-dontskipnonpubliclibraryclasses
# 指定不去忽略包可見的庫類的成員
-dontskipnonpubliclibraryclassmembers
#不進行優(yōu)化,建議使用此選項叹誉,
-dontoptimize
# 不進行預校驗,Android不需要,可加快混淆速度鸯两。
-dontpreverify
# 屏蔽警告(忽略警告,否則打包可能會不成功)
-ignorewarnings
# 指定混淆是采用的算法长豁,后面的參數(shù)是一個過濾器
# 這個過濾器是谷歌推薦的算法钧唐,一般不做更改
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# 保護代碼中的Annotation不被混淆
-keepattributes *Annotation*
# 避免混淆泛型, 這在JSON實體映射時非常重要
-keepattributes Signature
# 拋出異常時保留代碼行號
-keepattributes SourceFile,LineNumberTable
# 保留sdk系統(tǒng)自帶的一些內(nèi)容
-keepattributes Exceptions,InnerClasses,Deprecated,EnclosingMethod
#優(yōu)化時允許訪問并修改有修飾符的類和類的成員,這可以提高優(yōu)化步驟的結果匠襟。
# 比如钝侠,當內(nèi)聯(lián)一個公共的getter方法時,這也可能需要外地公共訪問酸舍。
# 雖然java二進制規(guī)范不需要這個帅韧,要不然有的虛擬機處理這些代碼會有問題。當有優(yōu)化和使用-repackageclasses時才適用父腕。
#指示語:不能用這個指令處理庫中的代碼弱匪,因為有的類和類成員沒有設計成public ,而在api中可能變成public
-allowaccessmodification
#當有優(yōu)化和使用-repackageclasses時才適用。
-repackageclasses ''
# 混淆時記錄日志(打印混淆的詳細信息)
# 這句話能夠使我們的項目混淆后產(chǎn)生映射文件
# 包含有類名->混淆后類名的映射關系
-verbose
#############################################
#
# -默認保留
#
#############################################
# 保持哪些類不被混淆
#繼承activity,application,service,broadcastReceiver,contentprovider....不進行混淆
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.support.multidex.MultiDexApplication
-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 class android.support.** {*;}## 保留support下的所有類及其內(nèi)部類
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
#表示不混淆上面聲明的類璧亮,最后這兩個類我們基本也用不上萧诫,是接入Google原生的一些服務時使用的。
#----------------------------------------------------
# 保留繼承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
#表示不混淆任何包含native方法的類的類名以及native方法名枝嘶,這個和我們剛才驗證的結果是一致
-keepclasseswithmembernames class * {
native <methods>;
}
#這個主要是在layout 中寫的onclick方法android:onclick="onClick"帘饶,不進行混淆
#表示不混淆Activity中參數(shù)是View的方法只估,因為有這樣一種用法干签,在XML中配置android:onClick=”buttonClick”屬性,
#當用戶點擊該按鈕時就會調(diào)用Activity中的buttonClick(View view)方法卿樱,如果這個方法被混淆的話就找不到了
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
#表示不混淆枚舉中的values()和valueOf()方法竞阐,枚舉我用的非常少缴饭,這個就不評論了
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#表示不混淆任何一個View中的setXxx()和getXxx()方法,
#因為屬性動畫需要有相應的setter和getter的方法實現(xiàn)骆莹,混淆了就無法工作了颗搂。
-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);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#表示不混淆Parcelable實現(xiàn)類中的CREATOR字段,
#毫無疑問幕垦,CREATOR字段是絕對不能改變的丢氢,包括大小寫都不能變傅联,不然整個Parcelable工作機制都會失敗。
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 這指定了繼承Serizalizable的類的如下成員不被移除混淆
-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();
}
# 保留R下面的資源
#-keep class **.R$* {
# *;
#}
#不混淆資源類下static的
-keepclassmembers class **.R$* {
public static <fields>;
}
# 對于帶有回調(diào)函數(shù)的onXXEvent疚察、**On*Listener的蒸走,不能被混淆
-keepclassmembers class * {
void *(**On*Event);
void *(**On*Listener);
}
# 保留我們自定義控件(繼承自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);
}
#
#----------------------------- 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);
}
#在app中與HTML5的JavaScript的交互進行特殊處理
#我們需要確保這些js要調(diào)用的原生方法不能夠被混淆,于是我們需要做如下處理:
-keepclassmembers class com.ljd.example.JSInterface {
<methods>;
}
#
# ----------------------------- 其他的 -----------------------------
#
# 刪除代碼中Log相關的代碼
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String, int);
public static int v(...);
public static int i(...);
public static int w(...);
public static int d(...);
public static int e(...);
}
# 保持測試相關的代碼
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**
# 記錄生成的日志數(shù)據(jù),gradle build時在本項根目錄輸出
# apk 包內(nèi)所有 class 的內(nèi)部結構
-dump proguard/class_files.txt
# 未混淆的類和成員
-printseeds proguard/seeds.txt
# 列出從 apk 中刪除的代碼
-printusage proguard/unused.txt
# 混淆前后的映射
-printmapping proguard/mapping.txt
#############################################
#
# -實體類 以及 Gson
# --------(實體Model不能混淆貌嫡,否則找不到對應的屬性獲取不到值)-----
#
#############################################
-dontwarn org.jbase.yxt.yyd.pyw.response.**
#對含有反射類的處理(gson反射解析)
-keep class org.jbase.yxt.yyd.pyw.response.** {*;}
-dontwarn com.google.gson.**
-keep class com.google.gson.**{*;}
-keep interface com.google.gson.**{*;}