Android开发-Apk瘦身-代码混淆

294 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

上一篇文章介绍了,apk的常用的几种瘦身方法,今天就其中的代码混淆,详细介绍下。

首先代码混淆不只是为了瘦身,更重要的是为了我们打包出去的apk文件的代码不被别人反编译出来,直接看到源码,防止我们的一些私密信息或者重要的key泄漏,造成一定的损失。

代码混淆

首先对于代码混淆,我们需要在我们的App目录下的build.gradle文件下开启混淆,但是一般我们只针对我们的release环境,所以在配置的时候,需要注意配置debug环境下不需要混淆,具体的配置如下:

buildTypes {
        release {
            debuggable true
            minifyEnabled Boolean.parseBoolean(needMinify)
            zipAlignEnabled Boolean.parseBoolean(needMinify)   //zipalign优化
            shrinkResources Boolean.parseBoolean(needMinify) // 是否去除无效的资源文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            debuggable true
            minifyEnabled false
            zipAlignEnabled false   //zipalign优化
            shrinkResources false // 是否去除无效的资源文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

这里我们在gradle.properties文件中新增了一个boolean类型的变量来全局控制这个开关。

needMinify = true

配置好开关,接下来我们就可以开始写我们的混淆文件了,配置中的proguard-rules.pro 就是我们混淆代码的存放位置。

一些出常用的配置:

image.png

剩下的就是根据自己项目里用到的类或者第三方源码,来配置混淆规则了,这里说到混淆规则,怎么样是混淆的,怎么样是不混淆的呢,这里需要介绍一下混淆的关键字:keep;混淆开启后默认是全部代码混淆,所以如果你不想被混淆的代码就需要通过keep关键字来控制,一般我们不混淆系统的support包还有系统的四大组件内容

image.png

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

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

# 保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}

# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**

#忽略警告
-ignorewarning

# 保留在Activity中的方法参数是view的方法,
# 这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{ public void *(android.view.View); }

# 保留我们自定义控件(继承自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);
}

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

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

#保持 Serializable 不被混淆并且enum 类也不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    !private <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

#不混淆资源类
-keepclassmembers class **.R$* {
    public static <fields>;
}
 -keep class **.R$* { *; }

这些是我项目中设置的一些通用的混淆代码。剩下的项目中的混淆,根据自己业务来设置,项目中友盟的混淆:

image.png

高德地图,glide等

image.png

bugly,eventBus:

# Bugly
-dontwarn com.tencent.bugly.**
-keep class com.tencent.bugly.** {*;}

# EventBus
-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

这些都不参与混淆,第三方很多混淆的规则在他们自己的接入文档中都有,大家在开发中可以自己找下。