Android开发之代码混淆

作者: Reathin | 来源:发表于2017-05-09 23:00 被阅读1274次

    应用混淆(ProGuard)

    ProGuard是一个免费的JAVA类文件压缩,优化,混淆器。

    它探测并删除没有使用的类,字段,方法和属性,它删除没有用的说明并使用字节码得到最大优化,它使用无意义的名字重命名类,字段和方法。

    我们先来介绍下ProGuard

    我们为啥要使用ProGuard?

    • 优化应用:创建紧凑的代码文档是为了更快的网络传输,快速装载和更小的内存占用;
    • 防止反向:创建的程序和程序库很难使用反向工程;
    • 预处理应用:充分利用JAVA的快捷加载的优点来提前检测和返回JAVA中存在的类文件。

    有些什么参数可用?

    • -include {filename} 从指定的文件中读取配置参数
    • -basedirectory {directoryname} 指定基础目录为以后相对的档案文件
    • -injars {class_path} 指定要处理的应用程序jar,war,ear的目录
    • -outjars {class_path} 指定处理完后要输出的jar,war,ear目录的名称
    • -libraryjars {class_path} 指定要处理的应用程序jar,war,ear和目录所需要的程序库文件
    • dontskipnonpubliclibraryclasses 指定不去忽略非公共的库类
    • dontskipnonpubliclibraryclassmebmbers 指定不去忽略可见的库类的成员

    上面提到了Jar、war、ear三种文件
    Jar、war、ear、在文件结构上,三者并没有什么不同,它们都采用zip或jar档案文件压缩格式。但是它们的使用目的有所区别:
    Jar文件(扩展名为. Jar,Java Application Archive)包含Java类的普通库、资源(resources)、辅助文件(auxiliary files)等。

    War文件(扩展名为.War,Web Application Archive)包含全部Web应用程序。在这种情形下,一个Web应用程序被定义为单独的一组文件、类和资源,用户可以对jar文件进行封装,并把它作为小型服务程序(servlet)来访问。

    Ear文件(扩展名为.Ear,Enterprise Application Archive)包含全部企业应用程序。在这种情形下,一个企业应用程序被定义为多个jar文件、资源、类和Web应用程序的集合。

    每一种文件(.jar, .war, .ear)只能由应用服务器(application servers)、小型服务程序容器(servlet containers)、EJB容器(EJB containers)等进行处理。

    有哪些保留选项?

    • -keep {Modifier} {class_specification} 保护指定的类文件和类的成员
    • -keepclassmembers {Modifier} {class_specification} 保护指定类的成员,如果此类受到保护他们会保护得更好
    • -keepclasseswithmembers {class_specification} 保护指定的类和类的成员,但条件是所有指定的类和类的成员是要存在的
    • -keepnams {class_specification} 保护指定的类的成员和名称(如果他们不会在压缩的过程中被删除)
    • -keepclassmembernames {class_specification} 保护指定类的成员的名称(如果他们不会在压缩的过程中被删除)
    • -keepclasseswithmembersnams {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,...} 保护给定的可选属性,例如LocalVariableTable(本地变量), SourceFile(源文件), InnerClasses(内部类)
    • -renamesourcefileattribute {string} 设置源文件中给定的字符串常量

    上面介绍了一下ProGuard的基本方法

    下面来介绍一下Android中的混淆文件。
    对应于项目下的proguard-rules.pro文件

    基本配置项

    1.指定要处理的应用程序jar,war,ear和目录所需要的程序库文件

    -libraryjars libs/apns_1.0.6.jar
    -libraryjars libs/armeabi/libBaiduMapSDK_v2_3_1.so
    -libraryjars libs/armeabi/liblocSDK4.so
    -libraryjars libs/core.jar
    -libraryjars libs/gesture-imageview.jar
    -libraryjars libs/gson-2.6.2.jar
    -libraryjars libs/infogracesound.jar
    -libraryjars libs/universal-image-loader-1.9.0.jar
    

    方法: libraryjars jar路径 ->libraryjars 项目中导入的jar包等
    现在Studio的话可以忽略此配置了。

    2.不优化输入的class文件,默认情况下是启用优化的

    #不优化输入的class文件,默认情况下是启用优化的
    -dontoptimize
    

    3.Proguard对你的代码进行迭代优化的次数 0~7,一直优化到代码不能被优化为止

    #Proguard对你的代码进行迭代优化的次数 0~7,一直优化到代码不能被优化为止
    -optimizationpasses 5
    

    4.跳过库中非public的类,可以加快proguard处理速度;但是有些类库包含从public类中继承来的非public类。这时如果加了这条会产生一个warning(find classes)

    -skipnonpubliclibraryclasses
    

    5.指定不去忽略非公共的库类

    -dontskipnonpubliclibraryclasses
    

    6.指定不去忽略包可见的库类的成员。

    -dontskipnonpubliclibraryclassmembers
    

    7.确定统一的混淆类的成员名称来增加混淆

    -useuniqueclassmembernames
    

    8.混淆时不会产生形形色色的类名

    -dontusemixedcaseclassnames
    

    9.混淆前认证,去掉可加快混淆速度

    -dontpreverify
    

    10.假如项目中有用到注解,保留注解,不混淆

    -keepattributes *Annotation*
    

    Android中的配置项

    1.保留所有的v4包中类不被混淆

    -keep class android.support.v4.**
    

    2.保留所有的v4包中接口不被混淆

    -keep interface android.support.v4.**
    

    3.保留系统中继承v4/v7包的类,不被混淆

    -keep class android.support.** { *; }
    -keep class android.support.v4.** { *; }
    -keep public class * extends android.support.v4.**
    -keep interface android.support.v4.app.** { *; }
    -keep class android.support.v7.** { *; }
    -keep public class * extends android.support.v7.**
    -keep interface android.support.v7.app.** { *; }
    -dontwarn android.support.**
    

    4.保留系统中继实现v4/v7包的接口,不被混淆

    -keep public class * implements android.support.v4.**
    -dontwarn android.support.v4.**
    

    5.所有的native方法不被混淆

    -keepclasseswithmembers class * {
        native <methods>;
    }
    

    6.自定义View构造方法不混淆

    -keepclasseswithmembers class * {
        public <init>(android.content.Context);
    }
    -keepclasseswithmembers class * {
        public <init>(android.content.Context,android.util.AttributeSet);
    }
    -keepclasseswithmembers class * {
        public <init>(android.content.Context,android.util.AttributeSet,int);
    }
    

    被Android Resource 文件引用到,名字已经固定,不能混淆。

    7.枚举不被混淆

    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    

    8.release版不打印log

    -assumenosideeffects class android.util.Log {
        public static *** d(...);
        public static *** v(...);
        public static *** i(...);
        public static *** e(...);
        public static *** w(...);
    }
    

    9.四大组件不能混淆

    -dontwarn android.support.v4.**
    -keep class android.support.v4.app.** { *; }
    -keep interface android.support.v4.app.** { *; }
    -keep class android.support.v4.** { *; }
    -keep public class * extends android.app.Application
    
    -dontwarn android.support.v7.**
    -keep class android.support.v7.internal.** { *; }
    -keep interface android.support.v7.internal.** { *; }
    -keep class android.support.v7.** { *; }
    
    -keep public class * extends android.app.Activity
    -keep public class * extends android.app.Fragment
    -keep public class * extends android.app.Application
    -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
    

    10.Design包不混淆

    -dontwarn android.support.design.**
    -keep class android.support.design.** { *; }
    -keep interface android.support.design.** { *; }
    -keep public class android.support.design.R$* { *; }
    

    11.确保JavaBean不被混淆-否则Gson将无法将数据解析成具体对象

    -keep class com.rair.circle.bean.** { *; }
    -keep class com.rair.circle.db.bean.** { *; }
    

    12.不混淆资源类

    -keepclassmembers class **.R$* {
        public static <fields>;
    }
    

    13.忽略警告

    -ignorewarning
    

    当我们使用第三方框架,jar包,如果配置混淆,都有对应的混淆配置提供。
    例如Jpush(极光推送)



    我们只要copy到项目混淆文件中就行

    最后

    混淆时是否记录日志

    -verbose  
    

    1.apk包内所有 class 的内部结构

    -dump class_files.txt  
    

    2.未混淆的类和成员

    -printseeds seeds.txt  
    

    3.列出从 apk 中删除的代码

    -printusage unused.txt  
    

    4.混淆前后的映射

    -printmapping mapping.txt  
    

    把混淆配置好后,记得在build.gradle打开混淆(设置为true)

       buildTypes {
            release {
                minifyEnabled true
                proguardFiles 'proguard-rules.pro'
            }
        }
    

    相关文章

      网友评论

        本文标题:Android开发之代码混淆

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