在Android開發完成即將發佈給用戶使用時,還有最後重要的一步:代碼混淆,這時候,Proguard就派上用場了,你們誰也不想辛辛苦苦寫的代碼太容易被別人反編譯過來,而Proguard就是幫咱們實現這一目的的工具。關於Proguard是什麼,有什麼特色,能夠在這個連接瞭解:http://proguard.sourceforge.net/,簡單來講,Proguard有以下幾大功能:java
流程以下圖所示:android
從剛剛網站連接能夠看到,Proguard能夠對Java代碼進行混淆從而達到基本的反編譯、逆向工程保護目的,另外還有一個針對Android的商業擴展版工具: DexGuard,對於APP開發來講,能夠進一步對代碼進行保護,例如:加密字符串、資源文件、本地庫等,而這些是Proguard缺乏的。這裏首先介紹Android Studio內置支持的Proguard。git
示例代碼GitHub上:https://github.com/linjk/TestProguard.gitgithub
新建一個Android工程後,Android Studio默認幫咱們新建了一個混淆文件,在release配置裏默認沒使能混淆,以下圖所示:web
在未進行混淆前,先生成一個發佈版本的app,用於和混淆後的app進行對比,命名爲:TestProguard-unproguard.apk算法
下面開始進行代碼混淆:數據庫
1. 修改app/build.gradle文件下buildTypes的release使用混淆功能,即:"minifyEnabled true"apache
2. 編輯proguard-rules.pro文件,編寫混淆規則:windows
2.1 通用混淆規則網絡
1 #代碼的壓縮級別, 0~7之間,默認爲5 2 -optimizationpasses 5 3 #包名不混合大小寫,混淆後的類名爲小寫(主要針對windows用戶的配置) 4 -dontusemixedcaseclassnames 5 #不去忽略非公共的庫類 6 -dontskipnonpubliclibraryclasses 7 #不去忽略非公共的庫的類的成員 8 -dontskipnonpubliclibraryclassmembers 9 #優化 不優化輸入的類文件 10 -dontoptimize 11 #不作預校驗(Android不須要此步驟,跳過可加快混淆速度) 12 -dontpreverify 13 #混淆後生成映射文件-->(包含有類名->混淆後類名的映射關係) 14 -verbose 15 #指定映射文件的名稱 16 -printmapping proguardMapping.txt 17 #-applymapping proguardMapping.txt 18 19 #混淆時所採用的算法,谷歌推薦,通常不改變 20 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 21 #保護代碼中的Annotation不被混淆,在使用如fastJSON時的實體映射 22 -keepattributes *Annotation* 23 #避免混淆泛型,在使用如fastJSON時的實體映射 24 -keepattributes Signature 25 #拋出異常時保留代碼行號 26 -keepattributes SourceFile,LineNumberTable 27 #忽略警告 ----- 不推薦所有忽略警告,若是確認哪些類和app無關,可使用 -dontwarn org.apache.http.**來忽略 28 -ignorewarning 29 #記錄生成的日誌數據,gradle build時在本項目根目錄輸出 30 #apk 包內全部 class 的內部結構 31 -dump class_files.txt 32 #未混淆的類和成員 33 -printseeds seeds.txt 34 #列出從 apk 中刪除的代碼 35 -printusage unused.txt 36 37 ################# Android默認的經常使用類保留不混淆 ###################### 38 #保留全部的本地native方法不被混淆 39 -keepclasseswithmembernames class * { 40 native <methods>; 41 } 42 #保持哪些類不被混淆 43 -keep public class * extends android.app.Fragment
#全部Activity子類不被混淆 44 -keep public class * extends android.app.Activity 45 -keep public class * extends android.app.Application 46 -keep public class * extends android.app.Service 47 -keep public class * extends android.content.BroadcastReceiver 48 -keep public class * extends android.content.ContentProvider 49 -keep public class * extends android.app.backup.BackupAgentHelper 50 -keep public class * extends android.preference.Preference 51 -keep public class * extends android.view.View
52 53 -keep public class com.android.vending.licensing.ILicensingService 54 #若是有引用v4包,添加下面這行 55 -keep public class * extends android.support.v4.app.Fragment.** {*;} 56 #保留在Activity中的方法參數是view的方法,從而在layout裏編寫的onClick不會被影響 57 -keepclassmembers class * extends android.app.Activity{ 58 public void *(android.view.View); 59 } 60 #枚舉類不能被混淆 61 -keepclassmembers enum * { 62 public static **[] values(); 63 public static ** valueOf(java.lang.String); 64 } 65 #保留自定義控件(繼承自view)不被混淆 66 -keep public class * extends android.view.View{ 67 ** get*(); 68 void set*(***); 69 public <init>(android.content.Context); 70 public <init>(android.content.Context, android.util,AttributeSet); 71 public <init>(android.content.Context, android.util,AttributeSet, int); 72 } 73 74 #保留Parcelable序列化的類不被混淆 75 -keep class * implements android.os.Parcelable{ 76 public static final android.os.Parcelable$Creator *; 77 } 78 79 #保留Serialable序列化的類不被混淆 80 -keepclassmembers class * implements java.io.Serializable{ 81 static final long serialVersionUID; 82 private static final java.io.ObjectStreamField[] serialPersistenFields; 83 private void writeObject(java.io.ObjectOutputStream); 84 private void readObject(java.io.ObjectInputStream); 85 java.lang.Object writeReplace(); 86 java.lang.Object readResolve(); 87 } 88 89 #對於R(資源)下的全部類機器方法不能被混淆 90 -keep class **.R$* { 91 *; 92 } 93 94 #對於帶有回調函數onXXEvent的方法不能被混淆 95 -keepclassmembers class * { 96 void *(**On*Event); 97 }
這部分是全部APP項目都通用的混淆規則,能夠直接Ctrl+c, Ctrl+v來使用。
2.2 針對特定APP的混淆規則
每一個APP工程都會按模塊來分包開發,如今用來測試的工程只有一個默認的Activivy類,就會簡單不少,可是仍是有很通用的模塊混淆規則的,以下:
1 #1. 保護實體類和成員 2 -keep public class cn.linjk.testproguard.beans.** { 3 public void set*(***); 4 public *** get*(); 5 public *** is*(); 6 } 7 8 #2. 很重要,內嵌類要保留(建議內嵌類單獨文件處理,以避免忘記致使後面調試查找麻煩) 9 -keep class cn.linjk.testproguard.activity.IndicatorActivity$*{ 10 *; 11 } 12 -keep public class * extends android.support.v7.app.AppCompatActivity 13 14 #3. 數據庫驅動不被混淆 15 #-keep class cn.linjk.testproguard.database.** {*;} 16 17 #3. 對webView的處理 18 -keepclassmembers class * extends anroid.webkit.webViewClient { 19 public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); 20 public boolean *(android.webkit.WebView, java.lang.String); 21 } 22 23 -keepclassmembers class * extends android.webkit.webViewClient { 24 public void *(android.webkit.webView, java.lang.String); 25 } 26 27 # 4. 網絡請求包不被混淆 28 -keep class cn.linjk.testproguard.networkservice.** {*;} 29 30 # 5. adapter不被混淆 31 -keep class cn.linjk.testproguard.adapter.** {*;} 32 33 #6. 第三方SDK的混淆處理(第三方SDK包通常都是通過混淆了,這裏是避免這些SDK的類和方法在該app中被混淆,在sdk官網都會列出混淆規則,複製粘貼就好了,*.so文件沒必要理會) 34 # butterknife 35 -keep class butterknife.** {*;} 36 -keep public class cn.jpush.** {*;} 37 -keep public class com.google.** {*;} 38 -keep public class com.readystatesoftware.viewbadger.** {*;} 39 40 -keep public class com.alipay.** {*;} 41 -dontwarn com.alipay.android.app.** 42 43 -keep public class com.mob.commons.** {*;} 44 -keep public class com.mob.tools.** {*;} 45 46 #7. layout資源目錄下自定義view不被混淆 47 -keep public class cn.linjk.testproguard.view.** {*;}
#8. JavaScript調用的java原生方法不被混淆
-keepclassmembers class cn.linjk.testproguard$JSCallInterfaces {
<methods>;
}
#9. 反射類處理,如*.class.getField()/getMethod()等方法
這兩部分規則複製到proguard-rules.pro,而後發佈便可進行混淆。
通過混淆後生成的apk,命名爲:TestProguard-proguard.apk,兩個apk文件對好比下:
能夠發現,通過混淆後的apk包體積更小。
如今來看看混淆後反編譯後的文件:
由於這個測試工程沒有什麼類,用的另一個項目的app來進行反編譯。能夠看到,這裏的類用了a、b、c等字母來替代了類名和方法,進一步能夠在smali文件看到:
這樣,別人就算反編譯了,也不知調用的是什麼方法,那咱們如何知道呢,在生成發佈包後,在app/build/output/release/mapping生成了輸出文件,包括哪些類哪些方法被混淆了,哪些類哪些方法被留下了,都有對應說明,咱們在查看線上bug時,就要靠它們來找到對應的應用奔潰地方來進行bug修復了。生成文件以下圖:
最後,要補充幾點重要的:
1. 混淆後的app必需要進行monkey測試,保證每一個頁面都路由到,看是否會產生奔潰,而後,在進行重要功能測試,如:推送、支付、掃描、定位等。
2. 多模塊的工程,在庫模塊也須要進行混淆,而後在app主工程保留庫的類和方法。