Android混淆工具——Proguard實踐

ElizabethLi 8年前發布 | 7K 次閱讀 Retrofit Android開發 移動開發

最近使用了一個非常高效和方便的混淆工具—— Proguard ,使用了這個工具混淆打包后,apk體積顯著的減少了,而且反編譯難度也加大了,所以寫個博客記錄一下這個混淆的過程。

說說什么是 Proguard 吧。

Proguard 介紹

官網 的介紹是: ProGuard 是一個免費的 Java 類文件縮小,優化,混淆和預驗證的工具。它檢測和刪除未使用的類,字段,方法和屬性;優化字節碼并刪除未使用的指令;它使用短的無意義的名稱重命名剩余的類,字段和方法。所得到的應用程序和庫更小,更快,并且更好地針對逆向工程進行優化。

而且 Proguard 已經集成在 Android studio 構建系統里了,可以通過簡單的代碼來實現構建apk的時候進行混淆打包。

Proguard 使用

首先,我們需要在項目里的 build.gradle 文件里配置 Proguard 。

buildTypes {
        release {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }


    }

可以看見,分別在 release 和 debug 兩種構建類型配置了 Proguard ,在 debug 配置是因為你可以直接編譯測試你混淆的效果,是否有影響正常功能的使用。

shrinkResources 是去除無效的資源文件,壓縮資源。

minifyEnabled 是開啟混淆。

這是默認的 Proguard 配置, proguard-rules.pro 是需要在你的項目里創建的文件,層級跟 build.gradle 文件一樣的,當然你可以隨意改他的文件名,只不過需要在配置代碼里面跟著修改,其實這個文件就是 Proguard 的自定義配置文件, 沒有這個文件你構建是會報錯的

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

Proguard 基本語法

-keep 不混淆類和成員或者被重命名

-keepnames 防止類和成員被重命名

-keepclassmembers 不混淆成員被移除或者被重命名

-keepnames 防止成員被重命名

-keepclasseswithmembers 不混淆擁有該成員的類和成員或者被重命名

-keepclasseswithmembernames 防止擁有該成員的類和成員被重命名

而且還支持通配符*

例如

不混淆某個類

-keep public class com.shadow.example.abc { *; }

不混淆某個包

-keep public class com.shadow.example.** { *; }

不混淆某個類的子類

-keep public class * extends com.shadow.exampl.abc { *; }

了解這些基本語法后,我們就來看一下自定義配置,沒有自定義混淆配置的話會構建出錯的。

Proguard 自定義配置

接下來介紹一下自定義混淆配置

以下是我在項目里使用的配置,我會在注釋里說明。

//--- 基礎混淆配置 ---

-optimizationpasses 5  //指定代碼的壓縮級別

-allowaccessmodification  //優化時允許訪問并修改有修飾符的類和類的成員

-dontusemixedcaseclassnames  //不使用大小寫混合

-dontskipnonpubliclibraryclasses  //指定不去忽略非公共庫的類

-verbose    //混淆時是否記錄日志

-ignorewarnings  //忽略警告,避免打包時某些警告出現,沒有這個的話,構建報錯

-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*  //混淆時所采用的算法

-keepattributes *Annotation* //不混淆注解相關

-keepclasseswithmembernames class * {  //保持 native 方法不被混淆
    native <methods>;
}

-keepclassmembers enum * {  //保持枚舉 enum 類不被混淆
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

//不混淆Parcelable 
-keep class * implements android.os.Parcelable {   
public static final android.os.Parcelable$Creator *;
}

//不混淆Serializable
-keep class * implements java.io.Serializable {*;}
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {*;}



-keepclassmembers class **.R$* { //不混淆R文件
    public static <fields>;
}

//不做預校驗,preverify是proguard的四個步驟之一,Android不需要preverify,去掉這一步能夠加快混淆速度。
-dontpreverify


-keepattributes Signature  //過濾泛型  出現類型轉換錯誤時,啟用這個


//--- 不能被混淆的基類 ---
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Fragment
-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 * extends android.view.View
-keep class org.xmlpull.v1.** { *; }



//--- 不混淆android-support-v4包 ---
-dontwarn android.support.v4.**
-keep class android.support.v4.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class * extends android.support.v4.** { *; }
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v4.widget
-keep class * extends android.support.v4.app.** {*;}
-keep class * extends android.support.v4.view.** {*;}
-keep public class * extends android.support.v4.app.Fragment


//不混淆繼承的support類
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**


//不混淆log 
-assumenosideeffects class android.util.Log {
    public static boolean isLoggable(java.lang.String, int);
    public static int v(...);
    public static int i(...);
    public static int w(...);
    public static int d(...);
    public static int e(...);
}


//保持Activity中參數類型為View的所有方法
-keepclassmembers class * extends android.app.Activity {
          public void *(android.view.View);
    }



//--- 不混淆第三方庫 這個可以去相關的第三方庫官網找尋混淆代碼 如果被混淆了會無法使用 ---


//Gson 
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
-keep class com.idea.fifaalarmclock.entity.***
-keep class com.google.gson.stream.** { *; }
-keep class com.你的bean.** { *; }


//OkHttp3
-dontwarn okhttp3.logging.**
-keep class okhttp3.internal.**{*;}
-dontwarn okio.**


//Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions


//RxJava RxAndroid
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
    long producerIndex;
    long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode consumerNode;
}


//微信
 -keep class com.tencent.mm.** {*;}


//Glide圖片庫
 -keep class com.bumptech.glide.**{*;}


 //友盟
 -keepclassmembers class * {
         public <init> (org.json.JSONObject);
 }

 -keep class com.umeng.onlineconfig.OnlineConfigAgent {
         public <fields>;
         public <methods>;
 }

 -keep class com.umeng.onlineconfig.OnlineConfigLog {
         public <fields>;
         public <methods>;
 }

 -keep interface com.umeng.onlineconfig.UmengOnlineConfigureListener {
         public <methods>;
 }


//Testin
-dontwarn com.testin.agent.**
-keep class com.testin.agent.** {*;}


//--- 一些特殊的混淆配置 ---


 //有用到WEBView的JS調用接口不被混淆
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
        public *;
   }


//對于帶有回調函數的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
       void *(**On*Event);
       void *(**On*Listener);
   }


//拋出異常時保留代碼行號 方便測試
-keepattributes SourceFile,LineNumberTable


//不混淆我們自定義控件(繼承自View)
 -keep public class * extends android.view.View{
     *** get*();
     void set*(***);
     public <init>(android.content.Context);
     public <init>(android.content.Context, android.util.AttributeSet);
     public <init>(android.content.Context, android.util.AttributeSet, int);
 }

你用了以上的配置文件,我相信大部分項目都是沒有問題的

在初次使用 Proguard 實現混淆配置的時候,會出現很多很多的坑,如果遇上了問題,可以通過報錯信息去谷歌一下,有可能會有很多你沒想到遺漏,一開始我也是踩了好多坑。。

不過,通過努力還是可以完成這個混淆實踐的,混淆后的 apk 體積會讓你驚訝的!

值得試試

最后

這是一個簡單的 Proguard 混淆實踐,記錄一下思路。

 

來自:http://www.jianshu.com/p/ea223e0f3737

 

 本文由用戶 ElizabethLi 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!