android中代码混淆

时间:2022-08-27 15:44:14

平时在build.gradle中看到

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

其中minifyEnabled true是设置代码混淆,而下面那句话就是说明代码混淆所使用的属性的文件,在proguard-rules.pro中,这个文件在module目录下, android中代码混淆


那什么是代码混淆?如果你的module是application的话,打包出来的是apk,如果你的module是android library的话,打包出来的是aar,如果别人反编译你的apk或者aar的时候,是可以看到你的源代码的,而设置了代码混淆,就可以让别人看不懂你的代码,举个例子,下面这张图是我反编译自己设置混淆的代码,左边那栏的a,b,c,d,e,f,g都不是原来的类名,右边的代码也都是abcd的字母,让人家难以看懂我的代码。

android中代码混淆


如果你有两个module,一个是app另一个是library,app依赖library,如果你设置library设置混淆的话,要注意几点:

1.要向app暴露app会调用library的代码,举个例子就是如果library中包含activity,而且这个activity要被app调用,那么要暴露这些activity,否则app调用时会说找不到该activity。

如果你还写了一些工具类的话,是需要暴露给app的话,都要暴露出来。

2.如果你的library中包含了一些libs/jar包的话,也需要暴露出来,否则会说找不到native method。

那么如何暴露呢

#暴露MyClass类,包括属性和方法
-keep class com.think.example.MyClass { *; }
#暴露com.think.example.others包下所有的类,包括他们的属性和方法
-keep class com.think.example.others.** { *; }
#在libs下面的jar包中的类,如果该包已经被混淆过,则不需要再次混淆,否则会出错。
-keep class com.example.mylibrary.** { *; }
#暴露你自定义的view,这些自定义的view在layout.xml中会用到,如果你不暴露的话,也会报错
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}



google默认下

-optimizationpasses 5                                                           # 指定代码的压缩级别
-dontusemixedcaseclassnames                                                     # 是否使用大小写混合
-dontskipnonpubliclibraryclasses                                                # 是否混淆第三方jar
-dontpreverify                                                                  # 混淆时是否做预校验
-verbose                                                                        # 混淆时是否记录日志
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*        # 混淆时所采用的算法

-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 com.android.vending.licensing.ILicensingService              # 保持哪些类不被混淆

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

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

如果你的library中包含了一些本地的jar包,那么需要在混淆中加入

-dontoptmize

就是在混淆时不要优化,proguard内部如何混淆的机制还不是很清楚,只是知道他会对你的代码进行优化,缩短变量的名字等等,如果你的项目未包含-dontoptimize,且又有本地jar包的话,会导致其他app接入你library打出的aar包会出现错误。

aar被混淆了,再接入app后,如果app也想混淆的话,则需要在app的proguard-rule.pro中将aar中已经被混淆过的类keep在外,否则对同一代码(library)进行多次混淆(aar中混淆,app中混淆)会出错。

另外,在混淆的时候碰到过一个坑,待我细细讲来:

我有一个类

public class SDKConstants{

      public static final String TAG="SDKConstants";

      public static final int code = 1;

}

现在我想在混淆的时候不要混淆SDKConstants.TAG这个属性,也就是不要混淆SDKConstants这个类名,也不要混淆TAG这个属性。

原来我在proguard-rules.pro是这么写的

-keep class com.think.example.SDKConstants{

      public static final String TAG;

      public static final int code;

}

在build的时候不出错,但是在工程中引用混淆的aar包时,却发现这个tag属性被混淆了,这和我刚才的代码不符啊,但是code这个变量却没有被混淆,不科学啊。

后来我仔细一想,int是基本类型,但是String却不是,是对象类型,我就去网上查,看到人家的代码都是这么写的

android中代码混淆

看到了么,java.lang.String来指明类型,于是我修改了我混淆的代码,如下:

-keep class com.think.example.SDKConstants{

      public static final java.lang.String TAG;

      public static final int code;

}

卧槽槽,成功了,真是坑爹,要mark下,防止以后出错。


那么如何反编译别人的代码呢?请看这篇博客 

Android反编译

下篇文章中会讲如何在混淆中再混淆    混淆中再混淆