一、定義
將代碼轉(zhuǎn)為一種難以理解和閱讀的形式。
二、原因
1、【優(yōu)化】它能優(yōu)化java的字節(jié)碼,使程序運行更快;
2、【壓縮】縮減App大小,在混淆過程中它會找出未被使用過的類和類成員并刪除他們;
3、【混淆】將代碼中的類、函數(shù)、變量名隨機變成無意義的代號形如:a,b,c...之類的,即使我們的APP即使被反編譯,也不容易理解和閱讀。
三、AndroidStudio混淆
Android SDK中自帶了混淆工具,在SDK -> tools ->proguard。
1、在app下build.gradle中將混淆打開。
android {
compileSdkVersion 23
buildToolsVersion "24.0.1"
defaultConfig {
}
buildTypes {
release {
minifyEnabled true //混淆打開
zipAlignEnabled true //優(yōu)化代碼
shrinkResources true //優(yōu)化資源
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
....
}
- minifyEnabled true :開啟混淆,刪除一些沒有引用到的代碼,開啟混淆編譯會變慢因此debug的時候需要關掉;
- zipAlignEnabled true:對打包的應用程序進行優(yōu)化,能優(yōu)化java字節(jié)碼,提高運行效率,發(fā)布之前一定要設置該項為true;
- shrinkResources true:刪除無用資源,也就是沒有被引用的文件(drawable,layout,并不是徹底刪除,而是保留文件名,但是沒有內(nèi)容);
shrinkResources要和minifyEnabled搭配使用,如果設置minifyEnabled 為false,shrinkResources設為true會報如下錯誤:
Removing unused resources requires unused code shrinking to be turned on.
更多使用說明可參考:shrinkResources 的使用
proguard-android.txt:AndroidStudio默認自動導入的規(guī)則,這個文件位于Android SDK根目錄\tools\proguard\proguard-android.txt,這里面是一些比較常規(guī)的不能被混淆的代碼規(guī)則。
proguard-rules.pro:對我們自己的項目需要特別定義混淆規(guī)則,它位于項目app目錄下面(app/ proguard-rules.pro),里面的內(nèi)容需要我們自己編寫。默認情況下會對所有代碼,包括第三方包都進行混淆,但有些代碼或者第三方包是不能混淆的,這就需要我們手動編寫混淆規(guī)則來保持不能被混淆的部分。
2、proguard-android.txt說明
下面默認的規(guī)則中指示了些需要保持不能別混淆的代碼。
# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
# 混淆時不使用大小寫混合類名
-dontusemixedcaseclassnames
# 不跳過library中的非public的類,混淆第三方jar
-dontskipnonpubliclibraryclasses
# 打印混淆的詳細信息
-verbose
# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize and preverify steps (and performs some
# of these optimizations on its own).
# 關閉優(yōu)化(原因見上邊的原英文注釋)
-dontoptimize
# 不進行預校驗,可加快混淆速度
-dontpreverify
# Note that if you want to enable optimization, you cannot just
# include optimization flags in your own project configuration file;
# instead you will need to point to the
# "proguard-android-optimize.txt" file instead of this one from your
# project.properties file.
# 保留注解中的參數(shù)
-keepattributes *Annotation*
# 不混淆如下兩個谷歌服務類
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
# 不混淆包含native方法的類的類名以及native方法名
-keepclasseswithmembernames class * {
native <methods>;
}
# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
# 不混淆View中的setXxx()和getXxx()方法,以保證屬性動畫正常工作
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
# We want to keep methods in Activity that could be used in the XML attribute onClick
# 不混淆Activity中參數(shù)是View的方法,例如,一個控件通過android:onClick="clickMethodName"綁定點擊事件,混淆后會導致點擊事件失效
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
# 不混淆枚舉類中的values()和valueOf()方法
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 不混淆Parcelable實現(xiàn)類中的CREATOR字段,以保證Parcelable機制正常工作
-keepclassmembers class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator CREATOR;
}
# 不混淆R文件中的所有靜態(tài)字段,以保證正確找到每個資源的id
-keepclassmembers class **.R$* {
public static <fields>;
}
# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
# 不對android.support包下的代碼警告(如果我們打包的版本低于support包下某些類的使用版本,會出現(xiàn)警告的問題)
-dontwarn android.support.**
# Understand the @Keep support annotation.
# 不混淆Keep類
-keep class android.support.annotation.Keep
# 不混淆使用了注解的類及類成員
-keep @android.support.annotation.Keep class * {*;}
# 如果類中有使用了注解的方法,則不混淆類和類成員
-keepclasseswithmembers class * {
@android.support.annotation.Keep <methods>;
}
# 如果類中有使用了注解的字段,則不混淆類和類成員
-keepclasseswithmembers class * {
@android.support.annotation.Keep <fields>;
}
# 如果類中有使用了注解的構造函數(shù),則不混淆類和類成員
-keepclasseswithmembers class * {
@android.support.annotation.Keep <init>(...);
}
3、混淆配置的語法
如果你能把上面proguard-android.txt說明看完,基本就可以照著寫出自己的混淆文件,如果需要了解更多可參考文章:ProGuard 最全混淆規(guī)則說明。
4、不能混淆代碼說明
四大組件和Application:Activity、service等和Application不能混淆?,F(xiàn)在的系統(tǒng)已經(jīng)配置為混淆時候會保留Android系統(tǒng)組件;
使用反射的類:因為代碼混淆,類名、方法名、屬性名都改變了,而反射它還是按照原來的名字去反射,結果程序崩潰。
注解:因為注解也用到了java反射,所以不能混淆。
自定義View:因為被Android Resource 文件引用到的,名字已經(jīng)固定,也不能混淆。自定義view是帶了包名寫在xml布局中的。
JavaBean 類:使用了 Gson 之類的工具要使 JavaBean 類即實體類不能混淆。因為json轉(zhuǎn)換用到了java反射。
泛型:泛型不能混淆。
自定義控件類:控件類的get/set方法和構造函數(shù)不能混淆。
內(nèi)部類:如果內(nèi)部類會被外部調(diào)用到,那么也不能混淆。
使用了枚舉的類:使用了枚舉要保證枚舉不被混淆。
第三方庫類:對第三方庫中的類不進行混淆。
包含native方法類:不混淆任何包含native方法的,否則找不到本地方法。
屬性動畫兼容庫:屬性動畫兼容庫不能混淆。
在引用第三方庫的時候,一般會標明庫的混淆規(guī)則的,建議在使用的時候就把混淆規(guī)則添加上去,免得到最后才去找。
不混淆Rxjava/RxAndroid。
數(shù)據(jù)庫驅(qū)動。
5、混淆后調(diào)試
在Android studio 中生成release包的同時 build\outputs\mapping\release文件夾下也生成了4個文件:
configuration.txt :總的混淆規(guī)則。這個文件包含了打包過程中所有混淆規(guī)則的匯總。
mapping.txt :列出了原始的類,方法,和字段名與混淆后代碼之間的映射。
seeds.txt :列出了未被混淆的類和成員。
usage.txt : 列出了從apk中刪除的代碼。
根據(jù)上面文件信息,反推出原代碼邏輯問題。
使用retrace工具
該工具在sdk根目錄\tools\proguard\bin\retrace.sh,使用步驟:
保存crash日志,轉(zhuǎn)存到bug.txt中;
刪掉Crash日志中AndroidRuntime前面的信息;
打開命令窗口執(zhí)行命令:如: ./retrace.sh mapping.txt bug.txt