最近項目有點閑,考慮到以前的項目沒有做過混淆,只是用了加固軟件進行加固,為了安全性,準備給項目加上,這里做個總結(jié),都經(jīng)本人親自在項目實踐,說是為了安全性,這好像說大了,一來項目中沒用到什么特別的技術,二是大神真要弄你你也防不住呀,這樣做只是為了讓閑著的自己心安理得一點,哈哈哈。。。
Android項目在完工發(fā)布時,需要對代碼和資源文件進行混淆,目的有兩個:
1、減小壓縮包的體積
2、防止代碼被反編譯后惡意利用
Android Apk混淆分兩步走:
1、混淆代碼
2、混淆資源文件
混淆資源文件直接使用第三方的就夠了,看這個網(wǎng)址:
http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=42
我們再來看看混淆代碼。
混淆就是對發(fā)布出去的程序進行重新組織和處理,使得處理后的代碼與處理前代碼完成相同的功能,而混淆后的代碼很難被反編譯,即使反編譯成功也很難得出程序的真正語義。被混淆過的程序代碼,仍然遵照原來的檔案格式和指令集,執(zhí)行結(jié)果也與混淆前一樣,只是混淆器將代碼中的所有變量、函數(shù)、類的名稱變?yōu)楹喍痰挠⑽淖帜复?,在缺乏相應的函?shù)名和程序注釋的況下,即使被反編譯,也將難以閱讀。同時混淆是不可逆的,在混淆的過程中一些不影響正常運行的信息將永久丟失,這些信息的丟失使程序變得更加難以理解。
因為Android是使用Java開發(fā)的,所以開發(fā)者可以使用ProGuard對代碼進行混淆。SDK已經(jīng)集成了ProGuard工具,開發(fā)者可以從SDK目錄下的\tools\proguard目錄中進行查看。
ProGuard是一個免費的Java類文件收縮,優(yōu)化,混淆和預校驗器。它可以檢測并刪除未使用的類,字段,方法和屬性。它可以優(yōu)化字節(jié)碼,并刪除未使用的指令。它可以將類、字段和方法使用短無意義的名稱進行重命名。最后,預校驗的Java6或針對Java MicroEdition的所述處理后的碼。
ProGuard默認會對第三方庫也進行混淆的,而第三方庫有的已經(jīng)混淆過了,有的使用了Java反射技術,所以我們在進行代碼混淆的時候要排除這些第三方庫。排除對第三方庫的混淆需要在混淆規(guī)則文件(通常是:proguard-project.txt或proguard.cfg或proguard-rules.pro或proguard-rules.txt也可以是其它的文件名只要在配置文件中將含有混淆規(guī)則的文件名配置進去就行了)中添加如下規(guī)則:
1.如果使用了Gson之類的工具要使JavaBean類即實體類不被混淆。
2.如果使用了自定義控件那么要保證它們不參與混淆。
3.如果使用了枚舉要保證枚舉不被混淆。
4.對第三方庫中的類不進行混淆
這里看一下具體的規(guī)則:
-optimizationpasses 7 #指定代碼的壓縮級別 0 - 7
-dontusemixedcaseclassnames #是否使用大小寫混合
-dontskipnonpubliclibraryclasses #如果應用程序引入的有jar包,并且想混淆jar包里面的class
-dontpreverify #混淆時是否做預校驗(可去掉加快混淆速度)
-verbose #混淆時是否記錄日志(混淆后生產(chǎn)映射文件 map 類名 -> 轉(zhuǎn)化后類名的映射
-optimizations !code/simplification/arithmetic,!field/,!class/merging/ #淆采用的算法
-keep public class * extends android.app.Activity #所有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.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService #指定具體類不要去混淆
-keepclasseswithmembernames class * {
native < methods>; #保持 native 的方法不去混淆
}
-keepclasseswithmembers class * {
public < init>(android.content.Context, android.util.AttributeSet); #保持自定義控件類不被混淆,指定格式的構(gòu)造方法不去混淆
}
-keepclasseswithmembers class * {
public < init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View); #保持指定規(guī)則的方法不被混淆(Android layout 布局文件中為控件配置的onClick方法不能混淆)
}
-keep public class * extends android.view.View { #保持自定義控件指定規(guī)則的方法不被混淆
public < init>(android.content.Context);
public < init>(android.content.Context, android.util.AttributeSet);
public < init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclassmembers enum * { #保持枚舉 enum 不被混淆
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable { #保持 Parcelable 不被混淆(aidl文件不能去混淆)
public static final android.os.Parcelable$Creator *;
}
-keepnames class * implements java.io.Serializable #需要序列化和反序列化的類不能被混淆(注:Java反射用到的類也不能被混淆)
-keepclassmembers class * implements java.io.Serializable { #保護實現(xiàn)接口Serializable的類中,指定規(guī)則的類成員不被混淆
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient < fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-keepattributes Signature #過濾泛型(不寫可能會出現(xiàn)類型轉(zhuǎn)換錯誤,一般情況把這個加上就是了)
-keepattributes Annotation #假如項目中有用到注解,應加入這行配置
-keep class *.R$ { *; } #保持R文件不被混淆,否則,你的反射是獲取不到資源id的
-keep class **.Webview2JsInterface { *; } #保護WebView對HTML頁面的API不被混淆
-keepclassmembers class * extends android.webkit.WebViewClient { #如果你的項目中用到了webview的復雜操作 ,最好加入
public void *(android.webkit.WebView,java.lang.String,android.graphics.Bitmap);
public boolean *(android.webkit.WebView,java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebChromeClient { #如果你的項目中用到了webview的復雜操作 ,最好加入
public void *(android.webkit.WebView,java.lang.String);
}
對WebView的簡單說明下:經(jīng)過實戰(zhàn)檢驗,做騰訊QQ登錄,如果引用他們提供的jar,若不加防止WebChromeClient混淆的代碼,oauth認證無法回調(diào),反編譯基代碼后可看到他們有用到WebChromeClient,加入此代碼即可。
-keepclassmembernames class com.cgv.cn.movie.common.bean.** { *; } #轉(zhuǎn)換JSON的JavaBean,類成員名稱保護,使其不被混淆
關于如何配置忽略第三方jar,附上一個圖進行說明。
要想讓eclipse的混淆產(chǎn)生效果,就必須打開工程目錄的project.properties文件,默認如下:
將 proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt前面的#刪除,混淆就起作用了,如果沒有的話,隨便找一個工程將這個文件拷貝過來即可,或者直接將這句話復制到這個文件中即可。
基本規(guī)則大概如上所示,有一些是共用的,這里說一下eclipse的混淆,看一下我的混淆文件。
在release模式下打包apk時會自動運行ProGuard,這里的release模式指的是通過ant release命令或eclipse project->android tools->export signed(unsigned) application package生成apk。
在debug模式下為了更快調(diào)試并不會調(diào)用proguard。
如果是ant命令打包apk,proguard信息文件會保存于工程代碼下的/bin/proguard文件夾內(nèi);
如果用eclipse export命令打包,會在/proguard文件夾內(nèi)。其中包含以下文件:
mapping.txt
表示混淆前后代碼的對照表,這個文件非常重要。如果你的代碼混淆后會產(chǎn)生bug的話,log提示中是混淆后的代碼,希望定位到源代碼的話就可以根據(jù)mapping.txt反推。
每次發(fā)布都要保留它方便該版本出現(xiàn)問題時調(diào)出日志進行排查,它可以根據(jù)版本號或是發(fā)布時間命名來保存或是放進代碼版本控制中。
dump.txt
描述apk內(nèi)所有class文件的內(nèi)部結(jié)構(gòu)。
seeds.txt
列出了沒有被混淆的類和成員。
usage.txt
列出了源代碼中被刪除在apk中不存在的代碼。
下面再來看一下Android Studio應該怎么做?
只需要在工程的module的build.gradle里面將minifyEnabled設置為true即可。下面來看看我的混淆文件
混淆以后一定要注意測試,避免因為混淆而引入了不必要的bug。
這里還是要提醒一下,混淆的時候有些是不能混淆的:
顧名思義,不能混淆代碼如果被混淆了,就會出現(xiàn)錯誤。
1、需要反射的代碼
2、系統(tǒng)接口
3、Jni接口
4、需要序列號和反序列化的代碼(即實現(xiàn)Serializable接口的JavaBean)
5、與服務端進行元數(shù)據(jù)交互的JavaBean(JSON、XML中對應的類)
。。。。。。
后續(xù)更新
轉(zhuǎn)載自:http://blog.csdn.net/u014727709/article/details/70215254
歡迎start,歡迎評論,歡迎指正