How To Use Proguard in Android APP

  在Android開發完成即將發佈給用戶使用時,還有最後重要的一步:代碼混淆,這時候,Proguard就派上用場了,你們誰也不想辛辛苦苦寫的代碼太容易被別人反編譯過來,而Proguard就是幫咱們實現這一目的的工具。關於Proguard是什麼,有什麼特色,能夠在這個連接瞭解:http://proguard.sourceforge.net/,簡單來講,Proguard有以下幾大功能:java

  •   Shink :  掃描並移除代碼中無用的類、屬性字段、方法                         (第一步)
  • Optomize :  對字節碼進行優化,移除無用的指令                                        (第二步)
  • Obfuscate:  使用簡短、無心義的字母替換類名、屬性字段名等,達到混淆目的    (第三步)
  • Preverify  :  上面三步完成後,對其進行預校驗                                           (第四步)

  流程以下圖所示: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主工程保留庫的類和方法。

相關文章
相關標籤/搜索