文章目录

  • 前言
  • 一、什么是代码混淆
  • 好处
  • 坏处
  • 二、开启混淆
  • 1.修改build.gradle
  • 2.修改混淆文件
  • 常用混淆命令
  • 类修饰常用规则
  • 例子
  • 3.生成混淆结果文件
  • 4.混淆代码模板
  • 三、混淆注意事项



前言

本篇记录笔者对Android开发中代码混淆的认知

一、什么是代码混淆

关于代码混淆的定义,这里笔者选择自己认为讲的相对完整的话进行呈现

Java 是一种跨平台的、解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中。由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名、方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码。为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆。

混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功也很难得出程序的真正语义。被混淆过的程序代码,仍然遵照原来的档案格式和指令集,执行结果也与混淆前一样,只是混淆器将代码中的所有变量、函数、类的名称变为简短的英文字母代号,在缺乏相应的函数名和程序注释的况下,即使被反编译,也将难以阅读。同时混淆是不可逆的,在混淆的过程中一些不影响正常运行的信息将永久丢失,这些信息的丢失使程序变得更加难以理解。

混淆器的作用不仅仅是保护代码,它也有精简编译后程序大小的作用。由于以上介绍的缩短变量和函数名以及丢失部分信息的原因, 编译后 jar文件体积大约能减少25%

好处

根据以上定义,可以简单对混淆的好处和坏处总结如下

  • 防止反编译获取项目源码
  • 精简编译后的apk文件大小

坏处

混淆的坏处如下

  • 会延长编译时间,所以切记请勿在debug模式下开启混淆
  • 混淆会让代码失去可读性,且无法还原

二、开启混淆

1.修改build.gradle

将minifyEnabled的值改为true即开启:其中debug为测试版本,release为发布版本

java代码混淆的源码 代码混淆原理_ide

2.修改混淆文件

开启混淆后Android会用自带的混淆进行代码混淆,如在安装Android SDK的目录下的proguard-android.txt或proguard-android-optimize.txt文件为默认混淆文件。对于自己定义的混淆需要在proguard-rules.pro文件中进行配置:

常用混淆命令

java代码混淆的源码 代码混淆原理_java代码混淆的源码_02

类修饰常用规则
  • 类:需要使用完全限定名;
  • *:通配符,任意字符串,不包含包名分隔符(.);
  • **:通配符,任意字符串,包含包名分隔符(.);
  • extends:继承某类的类;
  • implement:实现某接口的类;
  • $:内部类;
  • :所有构造方法;
  • :所有成员变量;
  • :所有方法;
  • …:任意参数;
  • 修饰符:public private protected
例子

java代码混淆的源码 代码混淆原理_java_03

3.生成混淆结果文件

因为我们提供给别人的一般都是release版本的库,所以要在build.gradle中开启release版代码混淆,配置好混淆规则后在Android studio的Terminal界面输入:
gradlew assembleRelease 再回车进行编译打包,如果编译失败则检查配置的混淆规则。成功后即可得到混淆后的aar或apk文件:

4.混淆代码模板

将报错的或者自己不需要的删除即可,然后在最后添加自己不需要混淆的代码:

#---------这里提供一份这个lib中最好不要混淆的地方,前边的配置都差不多,主要是第三方包以及其他不需要混淆的代码----
#---------------------------------基本指令以及一些固定不混淆的代码--开始--------------------------------
 
#<基本指令>
-optimizationpasses 5
-dontskipnonpubliclibraryclassmembers
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-keepattributes *Annotation*,InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
#忽略警告
-ignorewarning
#记录生成的日志数据,gradle build时在本项目根目录输出apk 包内所有 class 的内部结构
-dump class_files.txt
#未混淆的类和成员
-printseeds seeds.txt
#列出从 apk 中删除的代码
-printusage unused.txt
#混淆前后的映射
-printmapping mapping.txt
#</基本指令>
 
#<基础>
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.support.multidex.MultiDexApplication
-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 public class com.android.vending.licensing.ILicensingService
-keep class android.support.** {*;}
#</基础>
 
#<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);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * {
   public void *(android.view.View);
}
#</view相关>
 
#<Serializable、Parcelable>
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
-keep public class * implements java.io.Serializable {*;}
 
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
#</Serializable、Parcelable>
 
#<R文件>
-keep class **.R$* {
 *;
}
#</R文件>
 
#<enum>
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
#</enum>
 
#<natvie>
-keepclasseswithmembernames class * {
    native <methods>;
}
#</natvie>
 
#---------------------------------基本指令以及一些固定不混淆的代码--结束-----------
 
#---------------------------------第三方包--开始-------------------------------
 
#<okhttp3.x>
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**
#</okhttp3.x>
 
#<retrofit2.x>
-dontnote retrofit2.Platform
-dontwarn retrofit2.Platform$Java8
-keepattributes Signature
-keepattributes Exceptions
-dontwarn okio.**
#</retrofit2.x>
 
#</okhttp3.x>
 
#<ButterKnife 7.0 以上>
 -keep class butterknife.** { *; }
 -dontwarn butterknife.internal.**
 -keep class **$$ViewBinder { *; }
 -keepclasseswithmembernames class * {
  @butterknife.* <fields>;
 }
 -keepclasseswithmembernames class * {
 @butterknife.* <methods>;
 }
#</ButterKnife 7.0 以上>
 
#<eventbus 3.0>
-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    <init>(java.lang.Throwable);
}
#</eventbus 3.0>
 
#<Gson>
-keep class com.google.gson.** {*;}
-keep class com.google.**{*;}
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
#</Gson>
 
#<glide>
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}
#</glide>
 
#<Rxjava RxAndroid>
-dontwarn rx.*
-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;
}
#</Rxjava RxAndroid>
 
#----------------------------------第三方包--结束--------------------------
 
#---------------------------------一些不要混淆的代码--开始-------------------
 
-keep class net.arvin.afbaselibrary.nets.** { *; }
-keep class net.arvin.afbaselibrary.data.** { *; }
 
#<反射>
-keep class net.arvin.afbaselibrary.nets.BaseNet{*;}
#</反射>
 
#<js>
 
#</js>
 
#<自定义View的类>
-keep class net.arvin.afbaselibrary.ui.views.** {*;}
#</自定义View的类>
 
#---------------------------------一些不要混淆的代码--结束-------------------

三、混淆注意事项

  • 混淆时对外暴露的接口层不能混淆,实体类不能混淆。