一:混淆是什么,該怎么做?
? ? ? 如果我們的app正常發布就必須要經歷混淆這一步,混淆可以使我們的app不那么容易被別人用反編譯工具破解,就算被破解,想要讀懂我們的源碼也是非常費勁的,因為混淆過的源碼的類和類成員會被隨機命名,代碼非常的亂和沒有規律,除非之前用keep進行了保護。
? ? ? 以我們的常用開發工具andorid studio 為例,Android Studio自身集成Java語言的ProGuard作為壓縮,優化,混淆和預校驗,并配合Gradle工具進行構建,我們只需要在工程應用目錄的build.gradle文件中設置minifyEnabled為true,然后可以到proguard-rules.pro文件中加入我們的混淆規則即可。如圖:
大家看到了,有兩個混淆文件,proguard-android.txt和proguard-rules.pro,proguard-rules.pro是我們需要自己編寫的混淆文件,proguard-android.txt是系統默認的,那么它在哪里呢?
用工具打開txt文件是這樣的效果:
這里說一下,你只要設置了minifyEnabled true開啟混淆,其他的壓縮,優化,預校驗就默認開啟了,那我們就可以開始proguard-rules.pro 文件的編寫了,如圖:
剛才是開啟混淆,那我們如何關閉,比如關閉壓縮,關閉優化呢?
總結一下:
我們通常說的proguard包括四個功能,shrinker(壓縮), optimizer(優化),obfuscator(混淆),preverifier(預校驗),他們的作用分別是:
shrink: 檢測并移除沒有用到的類,變量,方法和屬性;
optimize: 優化代碼,非入口節點類會加上private/static/final, 在字節碼級別執行優化,讓應用運行的更快。。
obfuscate: 增大反編譯難度,類和類成員會被隨機命名,除非用keep保護。
preverify: 預校驗代碼是否符合Java1.6或者更高的規范.
除了proguard之外,還有一個DexGuard,是專門用來優化混淆Android應用的。它包括資源混淆,字符串加密,類加密和dex文件分割等。它是在android編譯的時候直接產生Dalvik字節碼.......
混淆后我們會在工程目錄app/build/outputs/mapping/release(debug)下找到一個mapping.txt文件,這就是混淆規則,我們可以根據這個文件把混淆后的代碼反推回源本的代碼,所以這個文件比較重要,請妥善保管.
?
二:接下來我們來說一說混淆的基本規則:
但如果你用兩顆星,會發現,雖然類名被保持了,但里面的變量名啥的都變了,那如果我們既要本包保持類名和內容又要子包保存呢?
-keep class com.xzt.demotwo.**{*;}
剩下的我直接上代碼了,大家自己看吧:
-keep class com.xzt.demotwo.*? # 一顆星只保持本包的類名(不包含內容)-keep class com.xzt.demotwo.** # 二顆星表示保持本包和子包下的類名(不包含內容)
# 只保持本包的類名和內容-keep class com.xzt.demotwo.*{*;}#可以保持本包和子包的類名和內容-keep class com.xzt.demotwo.**{*;}#保持某個具體的類名不被混淆-keep class com.xzt.demotwo.MainActivity#保持某個具體的類及其內容不被混淆-keep class com.xzt.demotwo.MainActivity{*;}#保持類中特定內容,而不是所有的內容可以使用如下:-keep class com.xzt.demotwo.MainActivity{<init>; #匹配所有構造器<fields>; #匹配所有域<methods>; #匹配所有方法}?
你還可以在<fields>或<methods>前面加上private 、public、native等來進一步指定不被混淆的內容,如
-keep class com.xzt.demotwo{public <methods>;}
表示MainActivity下的所有public方法都不會被混淆,當然你還可以加入參數,比如以下表示用JSONObject作為入參的構造函數不會被混淆
-keep class com.xzt.demotwo {public <init>(org.json.JSONObject);}
#保持類中特定內容,還可以進一步縮小范圍-keep class com.xzt.demotwo.MainActivity{public; #保持該類下所有的共有方法不被混淆public *; #保持該類下所有的共有內容不被混淆private; #保持該類下所有的私有方法不被混淆private *; #保持該類下所有的私有內容不被混淆public(java.lang.String); #保持該類的String類型的構造方法}#在方法后加入參數,限制特定的構造方法-keep class com.xzt.demotwo.MainActivity{public (String);}#要保留一個類中的內部類及其內容不被混淆需要用 $ 符號-keep class com.xzt.demotwo.MainActivity$MyClass{*;}#使用Java的基本規則來保護特定類不被混淆,比如用extends,implement等這些Java規則,#如下:保持Android底層組件和類不要混淆-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 public class * extends android.view.View#如果不需要保持類名,只需要保持該類下的特定方法保持不被混淆,#需要使用keepclassmembers,而不是keep,因為keep方法會保持類名。#保持MainActivity類下test(String)方法不被混淆-keepclassmembernames class com.xzt.demotwo.MainActivity{public void test(java.lang.String);}
這里我附一張圖:
?
#如果擁有某成員,保留類和類成員?
-keepclasseswithmembernames class com.xzt.demotwo.MainActivity
注意事項
1、jni方法不可混淆,因為這個方法需要和native方法保持一致;
?-keepclasseswithmembernamesclass*{# 保持native方法不被混淆? ? native ;
}
2、反射用到的類不混淆(否則反射可能出現問題);
3、AndroidMainfest中的類不混淆,所以四大組件和Application的子類和Framework層下所有的類默認不會進行混淆。自定義的View默認也不會被混淆;所以像網上貼的很多排除自定義View,或四大組件被混淆的規則在Android Studio中是無需加入的;
4、與服務端交互時,使用GSON、fastjson等框架解析服務端數據時,所寫的JSON對象類不混淆,否則無法將JSON解析成對應的對象;
5、使用第三方開源庫或者引用其他第三方的SDK包時,如果有特別要求,也需要在混淆文件中加入對應的混淆規則;
6、有用到WebView的JS調用也需要保證寫的接口方法不混淆,原因和第一條一樣;
7、Parcelable的子類和Creator靜態成員變量不混淆,否則會產生Android.os.BadParcelableException異常;
-keepclass*implementsAndroid.os.Parcelable{# 保持Parcelable不被混淆? ? ? ? ? publicstaticfinalAndroid.os.Parcelable$Creator *;
}
8、使用enum類型時需要注意避免以下兩個方法混淆,因為enum類的特殊性,以下兩個方法會被反射調用。
-keepclassmembersenum* {publicstatic**[] values();publicstatic**valueOf(java.lang.String);?
}
?
作者:薛之濤
鏈接:https://www.jianshu.com/p/fcb7672ec401
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。