Java 混淆那些事(四):玩转 ProGuard 过滤器
2019-03-20 本文已影响0人
QuincySx
本文已授权微信公众号「玉刚说」独家发布。
欢迎大家来看「Java 混淆那些事」的第四篇,到目前我们现在已经可以进行编写混淆规则了,但是有个很严重问题,我们写的规则会出现很多重复的 keep 规则,我们随便举几个例子。
- 所有 Event 结尾的类里面的所有内容都不能混淆。
- 所有 XXX 子类中的 x() 方法都不混淆。
...
那么这些问题有没有什么办法来解决呢?有,就是今天我们要讲的过滤器。
类规范模板
先放张上一篇博客提到的图,讲到后面我们需要参考。
过滤器
过滤器是什么呢?就是类似正则的规则过滤器。
首先我先把几种不同类型的过滤器用几张表格列出来,然后讲述一下功能。这一篇我能用话说明白的绝对不用代码。自我感觉在博客中放代码体验太差了。
类相关的过滤器
1. 类名过滤器
符号 | 功能 |
---|---|
? | 可以匹配任意一个字符,但是 package 的分隔符(.)除外,例如:com.example.T?st ,可以匹配 com.example.Test ,com.example.T2st ,但是 com.example.T12st 、com.example.Tst 和 com.example.T.st 不可以。 |
* | 可以匹配任意一部分连续的字符,但是 package 的分隔符(.)除外,例如 com.example.*Test ,可以匹配 com.example.Test ,com.example.AnyTest ,但是 com.example.xxx.Test 不可以,还有一个特例 com.example.* 只能匹配当前包下的类,com.example.xxx.Test 就匹配不到。 |
** | 可以匹配任意一部分连续的字符,例如 com** ,可以匹配 com.Test ,com.example.Test ,com.example.java.Test
|
<n> | 在同一匹配规则中匹配和第 n 个通配符一致的内容。例如:*Any<1> ,可以匹配到 TestAnyTest ,TestAnytest 不可以。 |
2. 字段和方法名过滤器
符号 | 功能 |
---|---|
<init> | 匹配所有构造方法 |
<fields> | 匹配所有字段方法 |
<methods> | 匹配所有方法 |
* | 匹配所有方法和字段,包括构造方法。 |
? | 匹配方法名称中的任何单个字符。 |
<n> | 在同一匹配规则中匹配和第 n 个通配符一致的内容。 |
注:
- <fields> 用法如下,就代表所有字段。
-keep class DownloadClient {
<fields>;
}
- <methods> 用法如下,就代表所有方法。
-keep class DownloadClient {
<methods>;
}
看到了 <fields>、<methods> 的用法,参照文章开始的类规范的图可知,我们可以再前面添加 public 之类的关键字,但是后面是添加不了东西的。
<init> 的后面必须存在一个参数列表。
3. 类型过滤器
符号 | 功能 |
---|---|
% | 匹配所有基本类型 |
? | 匹配类名中的任何单个字符 |
* | 匹配不包含包分隔符的类名的任何部分。 |
** | 匹配类名的任何部分,可能包含任意数量的包分隔符。 |
*** | 匹配所有任何类型 |
... | 匹配任何类型任何数量的参数 |
<n> | 在同一匹配规则中匹配和第 n 个通配符一致的内容。 |
注:?,* 和 ** 通配符不可以匹配原始类型,比如:int,float。包装类和普通类是可以匹配的,比如:Integer,String。
文件相关的过滤器
除了上述和类相关的过滤器之外还有和文件过滤器,如果需要自己独立使用 ProGuard 写配置规则或者需要写其他的配置,那么肯定要写那些文件需要输入,输出到哪等等的问题,往往我们的项目很大不能挨个文件去写规则,所以就需要过滤器。下一章我们介绍一些不常用的 ProGuard 选项,也能用到文件相关的过滤器。
符号 | 功能 |
---|---|
? | 匹配文件名中的任何单个字符。 |
* | 匹配不包含目录分隔符的文件名的任何部分。 |
** | 匹配文件名的任何部分,可能包含任意数量的目录分隔符。 |
小结
到此基本的过滤器我们也大概了解了,大家可以看到有好几个长得一样的过滤器,但是作用在不同地方功能不同,我们仔细去看他们的作用,其实也没有什么本质变化。
那么,我们回归一下先前的两个问题。
- 所有 Event 结尾的类里面的所有内容都不能混淆。
-keep class **Event { *; }
- 所有 XXX 子类中的 x() 方法不混淆。
-keep class ** extends XXX {
void x();
}
但是 XXX 类被混淆了,如果不想 XXX 被混淆,那就在另写一条匹配规则。