美文网首页
自定义 Android Gradle -- 使用混淆

自定义 Android Gradle -- 使用混淆

作者: 冯可乐同学 | 来源:发表于2022-01-11 17:47 被阅读0次

    ----《Android Gradle 权威指南》学习笔记

    总目录:Gradle 学习系列 -- 目录

    上一篇:Android Gradle -- 隐藏签名文件信息

    下一篇:自定义 Android Gradle -- 启动 zipalign 优化

    1. 简介

    代码混淆时一个非常有用的功能,它不仅能优化代码,让 apk 包变得更小,还可以混淆原来的代码,让反编译的人不容易看明白业务逻辑,很难分析。一般情况下发布到市场的版本是要混淆的。调试的版本不用混淆,因为混淆后就无法断点跟踪调试了。

    2. 开启混淆

    要启用混淆,只需把 BuildType 的属性 miniEnabled 的值设置为 true 即可:

    buildTypes {
            release {
                ......
                minifyEnabled true
            }
        }
    

    3. Proguard 配置

    开启了代码混淆之后,Android Gradle 还不知道按何种规则进行混淆,不知道要保留哪些类不混淆,要做到这些就需要 Proguard 配置文件了。指定 Proguard 配置文件可以使用 proguardFile 方法,也可以使用 proguardFiles 方法。这个根据实际情况而定,看是需要指定一个还是想同时指定多个。

    4. 默认的 Proguard 配置文件

    AndroidStudio 中默认指定了 Proguard 配置文件:

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

    proguardFiles 加载了两个文件:getDefaultProguardFile(‘proguard-android.txt’)表示默认文件,这个文件是 sdk 自带的,有一些通用的配置;但是如果 apk 需要更加严格的加密,可以在 proguard-rules.pro 文件中进行更加详尽的配置。
    其中:

    • proguard-android.txt 文件在 SDK 中,具体的路径为:${sdk}\tools\proguard\
    • 在SDK 中,还有一个配置文件:proguard-android-optimize.txt,一个是没有优化的,一个是优化的。
    • proguard-rules.pro 文件在 AndroidStudio 工程中,和 app 工程的 build.gradle 同级,如图: 7.7.png

    5. proguard-android.txt 内容

    # This is a configuration file for ProGuard.
    # http://proguard.sourceforge.net/index.html#manual/usage.html
    
    # 包名不混合大小写
    -dontusemixedcaseclassnames
    # 不忽略非公共的库类
    -dontskipnonpubliclibraryclasses
    # 输出混淆日志
    -verbose
    
    # Optimization is turned off by default. Dex does not like code run
    # through the ProGuard optimize and preverify steps (and performs some
    # of these optimizations on its own).
    # 不进行优化
    -dontoptimize
    # 不进行预检验
    -dontpreverify
    # Note that if you want to enable optimization, you cannot just
    # include optimization flags in your own project configuration file;
    # instead you will need to point to the
    # "proguard-android-optimize.txt" file instead of this one from your
    # project.properties file.
    
    # 不混淆注解(注解不能被混淆)
    -keepattributes *Annotation*
    # 不混淆指定类
    -keep public class com.google.vending.licensing.ILicensingService
    -keep public class com.android.vending.licensing.ILicensingService
    
    # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
    # 不混淆native的方法
    -keepclasseswithmembernames class * {
        native <methods>;
    }
    
    # keep setters in Views so that animations can still work.
    # see http://proguard.sourceforge.net/manual/examples.html#beans
    # 不混淆继承View的所有类的set和get方法
    -keepclassmembers public class * extends android.view.View {
       void set*(***);
       *** get*();
    }
    
    # We want to keep methods in Activity that could be used in the XML attribute onClick
    # 不混淆继承Activity的所有类的中的参数类型为View的方法
    -keepclassmembers class * extends android.app.Activity {
       public void *(android.view.View);
    }
    
    # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
    # 不混淆枚举类型的values和valueOf方法
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    
    # 不混淆继承Parcelable的所有类的CREATOR
    -keepclassmembers class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator CREATOR;
    }
    
    # 不混淆R类中所有static字段
    -keepclassmembers class **.R$* {
        public static <fields>;
    }
    
    # The support library contains references to newer platform versions.
    # Don't warn about those in case this app is linking against an older
    # platform version. We know about them, and they are safe.
    # 忽略兼容库的所有警告
    -dontwarn android.support.**
    
    # Understand the @Keep support annotation.
    # 不混淆指定的类及其类成员
    -keep class android.support.annotation.Keep
    
    # 不混淆使用注解的类及其类成员
    -keep @android.support.annotation.Keep class * {*;}
    
    # 不混淆所有类及其类成员中的使用注解的方法
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <methods>;
    }
    
    # 不混淆所有类及其类成员中的使用注解的字段
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <fields>;
    }
    
    # 不混淆所有类及其类成员中的使用注解的初始化方法
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <init>(...);
    }
    

    从上面的解析可以看出,proguard-android.txt 中只提供了基本的内容,在实际使用 ProGuard 时通常需要配置大量的规则。例如,引用的第三方库的混淆配置,不混淆自定义控件,不混淆反射的类等。

    6. proguard-android.txt 中的基础语法:

    -include {filename}    从给定的文件中读取配置参数   
    -basedirectory {directoryname}    指定基础目录为以后相对的档案名称   
    -injars {class_path}    指定要处理的应用程序jar,war,ear和目录   
    -outjars {class_path}    指定处理完后要输出的jar,war,ear和目录的名称   
    -libraryjars {classpath}    指定要处理的应用程序jar,war,ear和目录所需要的程序库文件   
    -dontskipnonpubliclibraryclasses    指定不去忽略非公共的库类。   
    -dontskipnonpubliclibraryclassmembers    指定不去忽略包可见的库类的成员。  
    
    保留选项   
    -keep {Modifier} {class_specification}    保护指定的类文件和类的成员   
    -keepclassmembers {modifier} {class_specification}    保护指定类的成员,如果此类受到保护他们会保护的更好  
    -keepclasseswithmembers {class_specification}    保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。   
    -keepnames {class_specification}    保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)   
    -keepclassmembernames {class_specification}    保护指定的类的成员的名称(如果他们不会压缩步骤中删除)   
    -keepclasseswithmembernames {class_specification}    保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)   
    -printseeds {filename}    列出类和类的成员-keep选项的清单,标准输出到给定的文件   
    
    压缩   
    -dontshrink    不压缩输入的类文件   
    -printusage {filename}   
    -whyareyoukeeping {class_specification}       
    
    优化   
    -dontoptimize    不优化输入的类文件   
    -assumenosideeffects {class_specification}    优化时假设指定的方法,没有任何副作用   
    -allowaccessmodification    优化时允许访问并修改有修饰符的类和类的成员   
    
    混淆   
    -dontobfuscate    不混淆输入的类文件   
    -printmapping {filename}   
    -applymapping {filename}    重用映射增加混淆   
    -obfuscationdictionary {filename}    使用给定文件中的关键字作为要混淆方法的名称   
    -overloadaggressively    混淆时应用侵入式重载   
    -useuniqueclassmembernames    确定统一的混淆类的成员名称来增加混淆   
    -flattenpackagehierarchy {package_name}    重新包装所有重命名的包并放在给定的单一包中   
    -repackageclass {package_name}    重新包装所有重命名的类文件中放在给定的单一包中   
    -dontusemixedcaseclassnames    混淆时不会产生形形色色的类名   
    -keepattributes {attribute_name,...}    保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and   
    
    InnerClasses.   
    -renamesourcefileattribute {string}    设置源文件中给定的字符串常量  
    

    7. 关键字包括:

    • keep 保留类和类中的成员,防止它们被混淆或者移除
    • keepnames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除
    • keepclassmembers 只保留类中的成员,防止它们被混淆或者移除
    • keepclassmembernames 只保留类中的成员,防止它们被混淆,但当成员没有被引用时会被移除
    • keepclasswithmembers 保留类和类中的成员,防止它们被混淆或者移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆
    • keepclasswithmembernames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆

    8. 通配符包括:

    field 匹配类中的所有字段
    method 匹配类中的所有方法
    init 匹配类中的所有的构造函数
    * 匹配任意长度字符,但不含包名分隔符(.),比如说我们的完整类名是com.example.test.MainActivtiy,使用com.*,或者com.example.*,都是无法匹配的,因为*无法匹配包名中的分隔符,正确的匹配方式是com.example.*.*,或者是com.example.test.*,这些都是可以的。但如果你不写任何其他内容,只有一个*,那就表示匹配所有的东西
    **匹配任意长度字符,并且含包名分隔符(.),比如android.support.**就可以匹配android.support包下所有的内容,包括任意长度的子包.
    ***匹配任意参数类型,比如void set(***)就能匹配任意传入的参数类型,*** get*()就能匹配任意返回值的类型
    … 匹配任意长度的任意参数类型,比如void set(…)就能匹配任意的void set(String a)或者是void set(String a,int b)等方法
    

    9. 注意点:

    • Java的反射不能混淆。因为代码混淆,类名、方法名、属性名都改变了,而反射它还是按照原来的名字去反射。
    • 注解用了反射,所以不能混淆。
    • 不混淆任何包含native方法的类的类名以及native方法名,否则找不到本地方法。
    • Activity更不能混淆,因为AndroidManifest.xml文件中是完整的名字,混淆后怎么找?
    • 自定义view也是带了包名写在xml布局中,给我换成a,怎么破? R文件混淆了,id没了,界面崩溃那时自然咯。
    • 一般在使用第三方框架,sdk时主要其给出的混淆方案。github第三方混淆方案

    10. 输出文件

    每次构建时 ProGuard 都会输出下列文件:

    • dump.txt 说明 APK 中所有类文件的内部结构。
    • mapping.txt 提供原始与混淆过的类、方法和字段名称之间的转换。
    • seeds.txt 列出未进行混淆的类和成员。
    • usage.txt 列出从 APK 移除的代码。
      这些文件保存在 modulename/build/outputs/mapping/release/ 中。
    相关代码:https://gitee.com/fzq.com/gradle-demos

    相关文章

      网友评论

          本文标题:自定义 Android Gradle -- 使用混淆

          本文链接:https://www.haomeiwen.com/subject/jdgcfrtx.html