• Android:代码混淆概念整理



    前言

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

    一、什么是代码混淆

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

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

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

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

    好处

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

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

    坏处

    混淆的坏处如下

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

    二、开启混淆

    1.修改build.gradle

    将minifyEnabled的值改为true即开启:其中debug为测试版本,release为发布版本
    在这里插入图片描述

    2.修改混淆文件

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

    常用混淆命令

    在这里插入图片描述

    类修饰常用规则

    • 类:需要使用完全限定名;

    • *:通配符,任意字符串,不包含包名分隔符(.);

    • **:通配符,任意字符串,包含包名分隔符(.);

    • extends:继承某类的类;

    • implement:实现某接口的类;

    • $:内部类;

    • :所有构造方法;

    • :所有成员变量;

    • :所有方法;

    • …:任意参数;

    • 修饰符:public private protected

    例子

    在这里插入图片描述

    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.** {*;}
    #
     
    #
    -keep public class * extends android.view.View{
        *** get*();
        void set*(***);
        public (android.content.Context);
        public (android.content.Context, android.util.AttributeSet);
        public (android.content.Context, android.util.AttributeSet, int);
    }
    -keepclasseswithmembers class * {
        public (android.content.Context, android.util.AttributeSet);
        public (android.content.Context, android.util.AttributeSet, int);
    }
    -keepclassmembers class * {
       public void *(android.view.View);
    }
    #
     
    #
    -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 *;
    }
    #
     
    #
    -keep class **.R$* {
     *;
    }
    #
     
    #
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    #
     
    #
    -keepclasseswithmembernames class * {
        native ;
    }
    #
     
    #---------------------------------基本指令以及一些固定不混淆的代码--结束-----------
     
    #---------------------------------第三方包--开始-------------------------------
     
    #
    -dontwarn com.squareup.okhttp3.**
    -keep class com.squareup.okhttp3.** { *;}
    -dontwarn okio.**
    #
     
    #
    -dontnote retrofit2.Platform
    -dontwarn retrofit2.Platform$Java8
    -keepattributes Signature
    -keepattributes Exceptions
    -dontwarn okio.**
    #
     
    #
     
    #
     -keep class butterknife.** { *; }
     -dontwarn butterknife.internal.**
     -keep class **$$ViewBinder { *; }
     -keepclasseswithmembernames class * {
      @butterknife.* ;
     }
     -keepclasseswithmembernames class * {
     @butterknife.* ;
     }
    #
     
    #
    -keepattributes *Annotation*
    -keepclassmembers class ** {
        @org.greenrobot.eventbus.Subscribe ;
    }
    -keep enum org.greenrobot.eventbus.ThreadMode { *; }
    -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
        (java.lang.Throwable);
    }
    #
     
    #
    -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.** { *; }
    #
     
    #
    -keep public class * implements com.bumptech.glide.module.GlideModule
    -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
      **[] $VALUES;
      public *;
    }
    #
     
    #
    -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;
    }
    #
     
    #----------------------------------第三方包--结束--------------------------
     
    #---------------------------------一些不要混淆的代码--开始-------------------
     
    -keep class net.arvin.afbaselibrary.nets.** { *; }
    -keep class net.arvin.afbaselibrary.data.** { *; }
     
    #<反射>
    -keep class net.arvin.afbaselibrary.nets.BaseNet{*;}
    #
     
    #
     
    #
     
    #<自定义View的类>
    -keep class net.arvin.afbaselibrary.ui.views.** {*;}
    #
     
    #---------------------------------一些不要混淆的代码--结束-------------------
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186

    三、混淆注意事项

    • 混淆时对外暴露的接口层不能混淆,实体类不能混淆。
  • 相关阅读:
    【C语言必知必会 | 子系列第六篇】深入剖析循环结构(2)
    查看docker容器IP地址
    表结构的操作【MySQL】
    Android---屏幕适配的处理技巧
    stm32cubemx安装(出现JDK配置错误,导致无法安装)
    Kafka请求发送分析
    C++ 函数
    Leetcode191. 位1的个数
    谷粒学院——Day08【课程发布-课程大纲和课程发布】
    GitHub | 在 GitHub 上在线展示 Vue 项目
  • 原文地址:https://blog.csdn.net/qjyws/article/details/126488356