Android混淆介绍

本文详细介绍了Android中的Proguard混淆机制,包括其作用、如何在build.gradle中开启混淆、基本混淆规则以及通用混淆配置。重点讲解了如何编写proguard-rules.pro以保持关键类和成员不被混淆,确保应用正常运行。
摘要由CSDN通过智能技术生成
Android混淆Proguard
一、简介

Android打包APP后为了增加反编译后阅读代码的难度,增加一些混淆操作,也就是将源代码中类名、方法名、属性名用其他的字符串(比如a、b、c)等,同时代码经过混淆压缩之后体积会明显的减小,达到优化APP的作用。

二、Proguard的作用
  • 压缩 Shrinking:默认开启,移除未使用的类和成员,并在优化Optimization 之后还会再次执行,移除无用的类,减少APP中方法数,也可避免造成64K的问题。
  • 优化 Optimization:默认开启,字节码层级进行优化,加快应用运行速度。
  • 混淆 Obfuscation :默认开启,增大反编译难度,除了在混淆文件中添加keep保持的类和类成员都会被随机命名。

他们都是可以在proguard-rules.pro文件中重新定义进行关闭,一般的话不要关闭它,要不然混淆就没有意义了

-dontshrink       # 关闭压缩
-dontoptimize     # 关闭优化
-dontobfuscate    # 关闭混淆
三、Android中开启混淆

如需要开启混淆,只需要在build.gradle文件中配置minifyEnabled true即可,剩下的需要在proguard-rules.pro编写混淆规则

android {
   ....
    buildTypes {
            release {
    //            zipAlignEnabled true
                minifyEnabled true//强制打开R8编译器 代码收缩、混淆和优化
                shrinkResources true //资源优化 移除无用资源
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
}

混淆开启后进行打包操作后,会在项目的proguard目录下生成3个文件,分别是

  • mapping.txt 这个文件说明项目中的类、属性、方法和混淆后的文件是怎么进行一一映射的,这个文件非常重要,如果被别人拿到了,就可以根据里面的映射规则进行代码的还原。
  • seeds.txt 没有混淆的类和成员
  • unsed.txt 列出从APP中删除的代码

注意:编写proguard-rules.pro混淆规则文件是为了保持部分类不会被混淆,防止因混淆造成类解析失败导致应用出现问题

四、基本规则
1)、语法关键词

keep 保持类和类成员不被移除或重命名

keepclassmembers 保持类成员不被移除或重命名

keepclasseswithmembers 如果某成员存在,保持该类和类成员不被移除或重命名

如果后面加上了names,则只会保持不被重命名

防止被移出或重命名防止被重命名保持范围
-keep-keepnames类和类成员
-keepclassmembers-keepclassmembernames仅类成员
-keepclasseswithmembers-keepclasseswithmembernames如果存在某成员,保留该成员和类
2)、各种匹配符
  • 星号 *

    匹配指定包下的类或者类的子类,写法如下:

-keep class yc.com.physician.model.bean.*;
-keep class yc.com.physician.model.bean.**

说明:

①、一个*号表示只保持该包(yc.com.physician.model.bean)下的类名不被混淆,而子包下的类名还是会混淆,比如bean下面有个subbean子包,它里面的类会被混淆。

②、两个*号表示保持该包(yc.com.physician.model.bean)下及该包下子包的包名不被混淆。

③、如果只写上面的配置,表示只保持类名不会混淆,而类中的方法和成员变量的名称还是被混淆改变了,如果既想保持类名,又想保持方法和成员变量不被混淆,需要使用以下方式:

-keep class yc.com.physician.model.bean.*{*;}

④、混淆规则中同样可以使用类似Java中extends、implements等规则进行配置

# 保持继承了BaseActivity的public修饰的类名不被混淆
-keep public class * extends yc.com.physician.base.BaseActivity 

# 内部类使用 $ 号,保持 PhysicianWebSubjectActivity 中 内部类 Test的所有 public 修饰的都不被混淆掉
-keepclassmembers class yc.com.physician.ui.activity.PhysicianWebSubjectActivity$Test{
    public *;
}

  • 特定匹配

  • <init>   # 匹配所有构造函数
    <fields>  # 匹配所有成员变量
    <methods> # 匹配所有的方法
    

    可以在这些匹配前面加上private、public进行更精细的限制范围,比如保持 User 类中 所有 public 方法不被混淆:

    -keep class yc.com.physician.ui.bean.User {
        public <methods>;
    }
    

    也可以指定类中某个特定的构造函数或方法不被混淆

    -keep class * extends com.bumptech.glide.module.AppGlideModule {
     <init>(...);
    }
    # 保持User类的public修饰,参数是String类型的方法不被混淆
    -keep class yc.com.physician.ui.bean.User {
        public <methods>(String);
    }
    
    
    3)、不能设置混淆的方法或成员
    • JNI 项目中jni方法不能混淆,因为需要和native方法保持一致

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

    反射用到的类不能混淆

  • Androidmanifest.xml 中的类不能混淆,所以四大组件和 Application子类,Framework 层下所有的类默认是不会进行混淆的。所以不需要手动添加混淆规则

  • 自定义的 View 默认不会被混淆

  • 与服务端交互解析成的实体对象不能设置混淆,否则不能解析出正确的对象。

  • -keep class yc.com.physician.model.bean.*{*;} # 自定义数据模型的bean目录
    
    

    引用第三方 SDK 时,需要根据它的文档加入对应的混淆规则。

  • Parceable 子类和 Creator 静态成员变量不能混淆,否则产生异常。

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

    枚举类需要注意避免以下两个方法混淆,因为enum类的特殊性,以下两个方法会被反射调用

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

    使用Webview时自定义的js接口调用类不能被混淆,

    -keepclassmembers class yc.com.physician.ui.activity.PhysicianWebSubjectActivity$Test{
        public *;
    }
    
    
    4)、通用的配置选项
    • -verbose 控制台输出详细的Proguard日志
    • -dontnote [class filter] 不提示过滤器中的类名。
    • -dontwarn [class filter] 不要警告过滤器中的类,忽略警告继续proguard。这个对于忽略第三方类库中的类的警告很有用。
    • -ignorewarnings 控制台输出所有未解析的应用和其他重要的问题,但是忽略,继续执行proguard。
    • -printconfiguration [filename] 指定输出所有的配置到指定文件中。这些配置包括混淆文件和替换的变量。
    • -dump [filename] 写出处理后的类文件的结构。
    五、通用的混淆规则

    有些混淆规则在任何APP中都使用,所以总结出来要用的时候直接复制就好

    #--------基本不用动区域--------------------------------------------
    #---------------------------------基本指令区----------------------------------
    #指定代码的压缩级别
    -optimizationpasses 5
    #包名不混合大小写
    -dontusemixedcaseclassnames
    #不去忽略非公共的库类
    -dontskipnonpubliclibraryclasses
     #优化  不优化输入的类文件
    #-dontoptimize
     #预校验
    -dontpreverify
     #混淆时是否记录日志
    -verbose
     # 混淆时所采用的算法
    -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
    #保护注解
    -keepattributes *Annotation*
    
    #忽略警告
    #-ignorewarning
    ##记录生成的日志数据,gradle build时在本项目根目录输出##
    #apk 包内所有 class 的内部结构
    -dump proguard/class_files.txt
    #未混淆的类和成员 打印出那些被keep住的类和成员,结果输出到指定文件里。
    -printseeds proguard/seeds.txt
    #列出从 apk 中删除的代码 打印指定输出那些没用的代码(dead code)到文件中。
    -printusage proguard/unused.txt
    #混淆前后的映射 打印混淆前后的名称对应关系到文件中,以便crash后进行对照。
    -printmapping proguard/mapping.txt 
    ########记录生成的日志数据,gradle build时 在本项目根目录输出-end######
    #如果引用了v4或者v7包
    -dontwarn android.support.**
    # ————————————————————————————————————————————————
    -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();
    }
    -keepclassmembers class **.R$* {
     pulic static <fields>;
    }
    
    -keepclassmembers class * {
        void *(*Event);
    }
    
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    -keep class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator *;
    }
    #// natvie 方法不混淆
    -keepclasseswithmembernames class * {
        native <methods>;
    }
    
    #保持 Parcelable 不被混淆
    -keep class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator *;
    }
    #----------------------------------------------------------------------------
    
    #---------------------------------webview------------------------------------
    -keepclassmembers class fqcn.of.javascript.interface.for.Webview {
       public *;
    }
    -keepclassmembers class * extends android.webkit.WebViewClient {
        public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
        public boolean *(android.webkit.WebView, java.lang.String);
    }
    -keepclassmembers class * extends android.webkit.WebViewClient {
        public void *(android.webkit.WebView, jav.lang.String);
    }
    #----------------------------------------------------------------------------
    #---------------------------------------------------------------------------------------------------
    #---------------------------------实体类---------------------------------
    
    
    

    转载:https://blog.csdn.net/a1sd1/article/details/121228444

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值