安卓代码混淆指南

混淆代码能有效提高项目反编译难度,同时还可以适当减少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注解之前我们需要先导入(在AndroidX依赖已经内置,无需引入下列依赖)

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()依然会被混淆。

好了,代码混淆总结差不多就这样了,希望对大家有帮助!

猜你喜欢

转载自blog.csdn.net/gs12software/article/details/48803823