目录
ProGuard概述
ProGuard工具通过移除无用的代码以及使用语义隐晦的名称来重命名类、变量和方法,从而达到压缩、优化和混淆代码的目的.由于ProGuard会使应用更难于被反向工程,因此当应用对安全性有较高的要求时,必须使用此工具.
ProGruad提供以下4个功能:
- 压缩(Shrink): 侦测并移除代码中无用的类、字段、方法和属性.
- 优化(Optimize): 对字节码进行优化,移除无用的指令.
- 混淆(Obfuscate): 使用a,b,c,d这样简短而无意义的名称,对类,字段和方法进行重命名.
- 预校验(Preverify): 在Java平台上对处理后的代码进行校验.
ProGuard的学习过程曲线还是有一点曲折,建议大家耐心的看完我的博客,肯定会对ProGuard机制有所收获.
ProGuard混淆规则
ProGuard之所以很强大,很大程度在于它的配置选项够多,各种组合可以产生不同的效果.
作为Android开发者,需要心里明确,ProGuard是没有一个最佳通用配置文件的.一般情况下,我们需要自己制定一些规则,然后逐步调试以达到最佳的效果.
ProGuard的混淆规则是利用“白名单”机制,通过“白名单”的配置,让ProGuard不去碰白名单中列出的类、变量或者方法.
常用语法
ProGuard的常用语法如下:
-keep [modifier…] class_specification: 不混淆指定的类(仅仅是只不混淆类的名字).
-keepclassmembers [modifier,,,] class_specification: 不混淆指定类的特定成员.
-keepclasseswithmembernames [modifier,,,] class_specification: 不混淆指定的类和它的成员.
-dontwarn [class_filter]: 不提示指定包名的混淆打包warning.
-keepattributes [attribute_filter]: 不混淆特定的属性.
-assumenosideeffects class_specification: 指定如果某些方法没有其他的作用,去掉不产生任何影响,则ProGuard可以在代码优化的过程中将其删除掉.通常用来删除Log日志打印语句.
通配符
在介绍ProGuard的常用规则之前,需要先介绍一下ProGuard中可能使用到的通配符,和正则表达式中元字符的使用有所不同,我们从一个具体的栗子入手:
-keep class android.** {*;}
我估计很多人都能理解{*;}部分的含义: 表示这个类的所有成员和方法.
但是两个*又代表什么呢?为什么不能用一个*代替呢?
要解释这个问题,就需要列举ProGuard中使用的通配符和其产生的作用:
- ? : 能匹配任意一个字符,但是不能表示package的分隔符,即..
- * : 能匹配任意n个字符,但是不能表示package的分隔符,即.
- ** : 能匹配任意n个字符,并且可以表示package的分隔符.
- % : 能匹配任何原始类型,如boolean、int等,但是不能表示void.
- *** : 能匹配任意类型,包括原始类型和非原始类型,数组类型和非数组类型.
- … : 能匹配任何数量的任何参数.
有了上面通配符规则介绍,我们就能知道,为了能够匹配到任意以android.开头的package,所以才使用了**.
常用规则
针对Android程序,ProGuard还是有一些常用规则来遵守的,具体如下.
Android framework class都是需要保留的,因为这些子类都有可能被外部调用.参考规则如下:
# keep framework class
-keep public class * extends android.app.Activity
-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.preference.Preference
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public