proguard混淆

为了防止开发APP的重要code 被泄露,我们往往需要混淆(Obfuscation code ), 也就是把方法,字段,包和类这些java 元素的名称改成无意义的名称,这样代码结构没有变化,还可以运行,但是想弄懂代码的架构却很难。 proguard 就是这样的混淆工具,它可以分析一组class 的结构,根据用户的配置,然后把这些class 文件的可以混淆java 元素名混淆掉。在分析class 的,同时他还有其他两个功能,删除无效代码(Shrinking 收缩),和代码进行优化 (Optimization Options)。

缺省情况下,proguard 会混淆所有代码,但是有些情况我们是不能改变java 元素的名称,否则就会这样就会导致程序出错。例如,用到反射的地方,我们代码依赖于系统的接口,比如被系统代码调用的回调方法,这种情况最复杂。这就需要我们在proguard-rules文件中告诉proguard 哪些java 元素是不能混淆的。

1. ProGuard配置

ProGuard关键字

保留选项(配置不进行处理的内容)

-keep {Modifier} {class_specification} 保留类和类中的成员,防止它们被混淆或移除。
-keepclassmembers {modifier} {class_specification} 保护指定类的成员,如果此类受到保护他们会保护的更好
-keepclasseswithmembers {class_specification} 保留类和类中的成员,防止它们被混淆或移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。
-keepnames {class_specification} 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。
-keepclassmembernames {class_specification} 只保留类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。
-keepclasseswithmembernames {class_specification} 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。

压缩

-dontshrink 不压缩输入的类文件
-whyareyoukeeping {class_specification}

优化

-dontoptimize 不优化输入的类文件
-assumenosideeffects {class_specification} 优化时假设指定的方法,没有任何副作用
-allowaccessmodification 优化时允许访问并修改有修饰符的类和类的成员

混淆

-dontobfuscate 不混淆输入的类文件
-obfuscationdictionary {filename} 使用给定文件中的关键字作为要混淆方法的名称
-overloadaggressively 混淆时应用侵入式重载
-useuniqueclassmembernames 确定统一的混淆类的成员名称来增加混淆
-flattenpackagehierarchy {package_name} 重新包装所有重命名的包并放在给定的单一包中
-repackageclass {package_name} 重新包装所有重命名的类文件中放在给定的单一包中
-dontusemixedcaseclassnames 混淆时不会产生形形色色的类名
-keepattributes {attribute_name,…} 保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-renamesourcefileattribute {string} 设置源文件中给定的字符串常量

输出:

-printseeds {filename} 列出类和类的成员-keep选项的清单,标准输出到给定的文件
-printusage {filename}

通配符

通配符 描述
匹配类中的所有字段
匹配类中的所有方法
匹配类中的所有构造函数
* 匹配任意长度字符,但不含包名分隔符(.)。比如说我们的完整类名是com.example.test.MyActivity,使用com.,或者com.exmaple.都是无法匹配的,因为无法匹配包名中的分隔符,正确的匹配方式是com.exmaple..,或者com.exmaple.test.,这些都是可以的。但如果你不写任何其它内容,只有一个*,那就表示匹配所有的东西。
** 匹配任意长度字符,并且包含包名分隔符(.)。比如proguard-android.txt中使用的-dontwarn android.support.**就可以匹配android.support包下的所有内容,包括任意长度的子包。
*** 匹配任意参数类型。比如void set()就能匹配任意传入的参数类型,* get*()就能匹配任意返回值的类型。
匹配任意长度的任意类型参数。比如void test(…)就能匹配任意void test(String a)或者是void test(int a, String b)这些方法。
  • 在android中在android Manifest文件中的activity,service,provider, receviter,等都不能进行混淆。一些在xml中配置的view也不能进行混淆,android提供的默认配置中都有。
  • keep和keepclasseswithmembers区别在于:keep关键字看到class *就认为应该将所有类名进行保留,不关心{}中的参数。而keepclasseswithmembers前提是{}的类中的成员必须存在,如果不存在则还是会混淆

不能混淆的东西

(1)Android 程序 ,下面这样代码混淆的时候要注意保留。
(2)Android系统组件,系统组件有固定的方法被系统调用。
(3) 被Android Resource 文件引用到的。名字已经固定,也不能混淆,比如自定义的View 。
(4)Android Parcelable ,需要使用android 序列化的。
(5) android.app.backup.BackupAgentHelper
(6) android.preference.Preference
(7) com.android.vending.licensing.ILicensingService
(8) Java序列化方法,系统序列化需要固定的方法。
(9) 枚举 ,系统需要处理枚举的固定方法。
(10)native 本地方法,不能修改本地方法名
(11)annotations 注释
(12)数据库驱动
(13)有些resource 文件
(14)用到反射的地方,比如调用aidl

常见问题

1、打包过程中,提示 Warning: can't find superclass or interface/ Warning: can't find referenced class等警告信息!
解决方法:
(1) 确保你的代码是否使用这个类,如果使用了,查看对应的第三方包有没有加上去,并且是否拉下来存在项目中
(2)如果该类存在,工程中确实使用了这个类,就在proguard中加上-keep class com.xx.yy.** { *;},让当前类不混淆。
(3) 确保报错的类没有在你的项目中使用到,可以使用"-dontwarn 类名正则表达式"屏蔽警告。
2、程序中使用泛型导致运行错误!
使用的泛型需要在混淆配置文件加了一个过滤泛型的语句,如下。
-keepattributes Signature

ProGuard的输出文件及用处

混淆之后,会给我们输出一些文件,在gradle方式下是在/build/proguard/目录下,ant是在/bin/proguard目录,eclipse构建在/proguard目录像。
分别有以下文件:

  • dump.txt 描述apk文件中所有类文件间的内部结构。
  • mapping.txt 列出了原始的类,方法,和字段名与混淆后代码之间的映射。
  • seeds.txt 列出了未被混淆的类和成员
  • usage.txt 列出了从apk中删除的代码

当我们发布的release版本的程序出现bug时,可以通过以上文件(特别时mapping.txt)文件找到错误原始的位置,进行bug修改。同时,可能一开始的proguard配置有错误,也可以通过错误日志,根据这些文件,找到哪些文件不应该混淆,从而修改proguard的配置。

注意:重新release编译后,这些文件会被覆盖,所以每次发布程序,最好都保存一份配置文件。一般去友盟统计等统计网站分析错误时,需要上传对应的mapping.txt才能看到错误信息对应的app原始类、方法、变量名。

proguard-android.txt 说明

# This is a configuration file for ProGuard.

# http://proguard.sourceforge.net/index.html#manual/usage.html

#混淆时不使用大小写混合类名
-dontusemixedcaseclassnames

#不跳过library中的非public的类
-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).

#不进行优化,建议使用此选项,因为根据proguard-android-optimize.txt中的描述,
#优化可能会造成一些潜在风险,不能保证在所有版本的Dalvik上都正常运行。
-dontoptimize

#不进行预校验。这个预校验是作用在Java平台上的,Android平台上不需要这项功能,去掉之后还可以加快混淆速度。
-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*

#不混淆下面声明的两个类,这两个类我们基本也用不上,是接入Google原生的一些服务时使用的。
-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方法的类的类名以及native方法名。
-keepclasseswithmembernames class * {
    native ;
}

# keep setters in Views so that animations can still work.

# see http://proguard.sourceforge.net/manual/examples.html#beans

#不混淆任何一个View中的setXxx()和getXxx()方法,因为属性动画需要有相应的setter和getter的方法实现,混淆了就无法工作了
-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的方法,因为有这样一种用法,在XML中配置android:onClick=”buttonClick”属性,
#当用户点击该按钮时就会调用Activity中的buttonClick(View 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字段,毫无疑问,CREATOR字段是绝对不能改变的,包括大小写都不能变,不然整个Parcelable工作机制都会失败
-keepclassmembers class * implements android.os.Parcelable {

  public static final android.os.Parcelable$Creator CREATOR;

}

#不混淆R文件中的所有静态字段,我们都知道R文件是通过字段来记录每个资源的id的,字段名要是被混淆了,id也就找不着了
-keepclassmembers class **.R$* {
    public static ;
}

# The support library contains references to newer platform versions.

# Dont warn about those in case this app is linking against an older

# platform version.  We know about them, and they are safe.

#对android.support包下的代码不警告,因为support包中有很多代码都是在高版本中使用的,如果我们的项目指定的版本比较低在打包时就会给予警告。不过support包中所有的代码都在版本兼容性上做足了判断,因此不用担心代码会出问题,所以直接忽略警告就可以了。
-dontwarn android.support.**

你可能感兴趣的:(proguard混淆)