1. 程式人生 > >Android Studio和eclipse混淆打包總結

Android Studio和eclipse混淆打包總結

最近專案有點閒,考慮到以前的專案沒有做過混淆,只是用了加固軟體進行加固,為了安全性,準備給專案加上,這裡做個總結,都經本人親自在專案實踐,說是為了安全性,這好像說大了,一來專案中沒用到什麼特別的技術,二是大神真要弄你你也防不住呀,這樣做只是為了讓閒著的自己心安理得一點,哈哈哈。。。
Android專案在完工釋出時,需要對程式碼和資原始檔進行混淆,目的有兩個:

1、減小壓縮包的體積
2、防止程式碼被反編譯後惡意利用

混淆就是對釋出出去的程式進行重新組織和處理,使得處理後的程式碼與處理前程式碼完成相同的功能,而混淆後的程式碼很難被反編譯,即使反編譯成功也很難得出程式的真正語義。被混淆過的程式程式碼,仍然遵照原來的檔案格式和指令集,執行結果也與混淆前一樣,只是混淆器將程式碼中的所有變數、函式、類的名稱變為簡短的英文字母代號,在缺乏相應的函式名和程式註釋的況下,即使被反編譯,也將難以閱讀。同時混淆是不可逆的,在混淆的過程中一些不影響正常執行的資訊將永久丟失,這些資訊的丟失使程式變得更加難以理解。
因為Android是使用Java開發的,所以開發者可以使用ProGuard對程式碼進行混淆。SDK已經集成了ProGuard工具,開發者可以從SDK目錄下的\tools\proguard目錄中進行檢視。
ProGuard是一個免費的Java類檔案收縮,優化,混淆和預校驗器。它可以檢測並刪除未使用的類,欄位,方法和屬性。它可以優化位元組碼,並刪除未使用的指令。它可以將類、欄位和方法使用短無意義的名稱進行重新命名。最後,預校驗的Java6或針對Java MicroEdition的所述處理後的碼。
ProGuard預設會對第三方庫也進行混淆的,而第三方庫有的已經混淆過了,有的使用了Java反射技術,所以我們在進行程式碼混淆的時候要排除這些第三方庫。排除對第三方庫的混淆需要在混淆規則檔案(通常是:proguard-project.txt或proguard.cfg或proguard-rules.pro或proguard-rules.txt也可以是其它的檔名只要在配置檔案中將含有混淆規則的檔名配置進去就行了)中新增如下規則:
1.如果使用了Gson之類的工具要使JavaBean類即實體類不被混淆。
2.如果使用了自定義控制元件那麼要保證它們不參與混淆。
3.如果使用了列舉要保證列舉不被混淆。
4.對第三方庫中的類不進行混淆
這裡看一下具體的規則:
-optimizationpasses 7 #指定程式碼的壓縮級別 0 - 7
-dontusemixedcaseclassnames #是否使用大小寫混合
-dontskipnonpubliclibraryclasses #如果應用程式引入的有jar包,並且想混淆jar包裡面的class
-dontpreverify #混淆時是否做預校驗(可去掉加快混淆速度)
-verbose #混淆時是否記錄日誌(混淆後生產對映檔案 map 類名 -> 轉化後類名的對映
-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); #保持自定義控制元件類不被混淆,指定格式的構造方法不去混淆
}

-keepclasseswithmembers class * {
public < init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View); #保持指定規則的方法不被混淆(Android layout 佈局檔案中為控制元件配置的onClick方法不能混淆)
}

-keep public class * extends android.view.View { #保持自定義控制元件指定規則的方法不被混淆
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 { #保護實現介面Serializable的類中,指定規則的類成員不被混淆
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 #過濾泛型(不寫可能會出現型別轉換錯誤,一般情況把這個加上就是了)

-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的簡單說明下:經過實戰檢驗,做騰訊QQ登入,如果引用他們提供的jar,若不加防止WebChromeClient混淆的程式碼,oauth認證無法回撥,反編譯基程式碼後可看到他們有用到WebChromeClient,加入此程式碼即可。

-keepclassmembernames class com.cgv.cn.movie.common.bean.* { ; } #轉換JSON的JavaBean,類成員名稱保護,使其不被混淆

關於如何配置忽略第三方jar,附上一個圖進行說明。
這裡寫圖片描述

要想讓eclipse的混淆產生效果,就必須開啟工程目錄的project.properties檔案,預設如下:
這裡寫圖片描述

將 proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt前面的#刪除,混淆就起作用了,如果沒有的話,隨便找一個工程將這個檔案拷貝過來即可,或者直接將這句話複製到這個檔案中即可。
基本規則大概如上所示,有一些是共用的,這裡說一下eclipse的混淆,看一下我的混淆檔案。
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

在release模式下打包apk時會自動執行ProGuard,這裡的release模式指的是通過ant release命令或eclipse project->android tools->export signed(unsigned) application package生成apk。
在debug模式下為了更快除錯並不會呼叫proguard。

如果是ant命令打包apk,proguard資訊檔案會保存於工程程式碼下的/bin/proguard資料夾內;
如果用eclipse export命令打包,會在/proguard資料夾內。其中包含以下檔案:

mapping.txt
表示混淆前後程式碼的對照表,這個檔案非常重要。如果你的程式碼混淆後會產生bug的話,log提示中是混淆後的程式碼,希望定位到原始碼的話就可以根據mapping.txt反推。
每次釋出都要保留它方便該版本出現問題時調出日誌進行排查,它可以根據版本號或是釋出時間命名來儲存或是放進程式碼版本控制中。

dump.txt
描述apk內所有class檔案的內部結構。

seeds.txt
列出了沒有被混淆的類和成員。

usage.txt
列出了原始碼中被刪除在apk中不存在的程式碼。

下面再來看一下Android Studio應該怎麼做?
這裡寫圖片描述

只需要在工程的module的build.gradle裡面將minifyEnabled設定為true即可。下面來看看我的混淆檔案
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

混淆以後一定要注意測試,避免因為混淆而引入了不必要的bug。
這裡還是要提醒一下,混淆的時候有些是不能混淆的:
顧名思義,不能混淆程式碼如果被混淆了,就會出現錯誤。

1、需要反射的程式碼

2、系統介面

3、Jni介面

4、需要序列號和反序列化的程式碼(即實現Serializable介面的JavaBean)

5、與服務端進行元資料互動的JavaBean(JSON、XML中對應的類)
。。。。。。

後續更新