安卓代碼混淆指南

混淆代碼能有效防止項目被反編譯,同時還可以適當減少apk的大小,在實際開發過程中尤爲重要,經過長時間的摸索,對代碼混淆有了一定的瞭解,下面寫下個人心得:

1. 代碼混淆的重要文件:proguard-rules.pro,如果你不小心刪掉了,從其他地方複製一個或自己創建一個。

2. 開啓混淆:

將build.gradle下的buildTypes->release->minifyEnabled設置爲true,即可開啓代碼混淆

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

3. proguard-rules.pro文件中各項配置的含義

在配置之前先說明下一些含義

  • -keep 保留目標不被混淆
  • *  通配符,表示所有,擴展:set*表示以set開頭,*onEvent* 表示含有onEvent關鍵字
  • <init> 表示構造方法
  • <methods> 類裏面的方法
  • <fields>  類裏面的屬性
  • $ 分隔符,標識內部類
  • -keepclasseswithmembers 保留類的成員

(配置項前加了#號表示註釋)

-optimizationpasses 5                                                           # 指定代碼的壓縮級別
-dontusemixedcaseclassnames                                                     # 是否使用大小寫混合
-dontskipnonpubliclibraryclasses                                                # 是否混淆第三方jar(建議註釋掉)
-dontpreverify                                                                  # 混淆時是否做預校驗
-verbose                                                                        # 混淆時是否記錄日誌
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*        # 混淆時所採用的算法

-keep public class * extends ****                                               # 保持哪些類不被混淆

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

-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);
}

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

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

#使用WebView時JavascriptInterface不被混淆,同時需要保證自定義的JS與原生交互的接口對象不被混淆
-keepattributes *JavascriptInterface*

#保證R文件不混淆
-keep public class [你的應用包名].R$*{ public static final int *;}

-keep class MyClass;                                                            # 保持自己定義的類不被混淆

 

4. 在proguard-rules.pro添加不需要混淆的代碼的申明:

a.將你不需要混淆的部分申明進來,有些類經過混淆會導致程序編譯不通過

-keep public class * extends android.app.Fragment  
-keep public class * extends android.app.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 * extends android.support.v4.**
-keep public class com.android.vending.licensing.ILicensingService

以上都是android基本組件和依賴包

b. Model層(實體)的類建議不混淆

-keep class  com.test.model.** { *; }

-keep class  com.test.domain.** { *; }  # 具體看實際項目包名和類

c.第三方的包都不建議混淆

第三方的library庫一般都已經混淆過,因此不必再次混淆

#示例:百度地圖SDK
-keep class com.baidu.** { *; }
-keep class vi.com.gdi.bgl.android.**{*;} 

#其他第三方lib混淆規則請參照它們的官方文檔

總結來說就是用-keep加上你想要保留的東西。

下面介紹另一種快速配置混淆的方法,使用註解@Keep


1.在使用@Keep註解之前我們需要先導入

compile 'com.android.support:support-annotations:{version}'

2.在proguard-rules.pro添加以下配置

-dontwarn android.support.annotation.Keep
#保留註解
-keepattributes *Annotation*
-keep @android.support.annotation.Keep class **  #保留@Keep註解的類以及它的屬性方法不被混淆

3.在我們想要保留的東西上面使用@Keep註解

@Keep
public class Test {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

在上面的代碼中,我們設置保留了Test這個類,那麼它在打包時就不會被混淆

如果我們只想保留它的屬性或者方法,類名混淆掉,那該怎麼辦呢?如下

在proguard-rules.pro修改如下配置:

-keep @android.support.annotation.Keep class **{
    @android.support.annotation.Keep <fields>;   #保留類裏面被@Keep註解的屬性
    @android.support.annotation.Keep <methods>;  #保留類裏面被@Keep註解的方法
}

然後在代碼中

public class Test {

    @Keep
    private String name;

    @Keep
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

上面代碼中,保留了name這個屬性和getName()這個方法不被混淆,類名Test和方法名setName()依然會被混淆。

好了,代碼混淆總結差不多就這樣了,希望對大家有幫助!

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章