Proguard的Keep使用方法

来源:互联网 发布:张清华预估量的算法 编辑:程序博客网 时间:2024/05/16 14:30

背景知识

Java代码存在互相引用的关系,构成一个网状关系.(个人理解)引用又分为两种:普通引用字符串引用(例如反射,native方法等).而java代码的执行入口点必然是采用的字符串引用(例如main等方法),因为外部想要执行此代码必须知道一个明确的入口点名字.

为了表述准确,类的成员变量下文称为域(Field),类的方法和成员变量统称成员(Member).

Proguard流程

  1. 压缩Shrunk:根据所有入口点建立引用关系网,去除网外的所有代码.

  2. 优化Optimize:对入口点以外所有的方法进行分析,将其中一部分方法变为final的,static的,private的或者内联的,从而提高执行效率.

  3. 入口点以外的类,方法,成员重构为简短的名字,可以进一步减小生成文件的大小并且混淆代码.

  4. Preverify:此处不讨论.

Proguard能够准确识别普通引用关系,但是只能识别部分典型的字符串引用(Class.forName方法等).而通过字符串引用的内容绝对不能改名字或者移除,所以就要使用keep配置proguard:

keep怎样使用

keep一共就有三个

  1. -keep [,modifier,…] class_specification

  2. -keepclassmembers [,modifier,…] class_specification

  3. -keepclasseswithmembers [,modifier,…] class_specification

其中modifier为可选配置,具体意义见下文,class_specification是类和成员的模板,用来指定应用keep规则的若干类及其成员.

  1. -keep可以保留指定的类名以及成员(就是把其当做应用的入口点)
  2. -keepclassmembers只能保留住成员而不能保留住类名
  3. -keepclasseswithmembers可以根据成员找到满足条件的所有类而不用指定类名(这样的类必定拥有所列出的所有成员),可以保留类名和成员名

不配置modifier时,上面的语句可以使保留的内容不被移除优化和混淆.

使用modifier

modifier共有三个可选值:

  • allowshrinking允许其被压缩,就是说指定的内容有可能被移除,但是如果没有被移除的话它也不会在后续过程中被优化或者混淆.
  • allowoptimization允许其被优化,但是不会被移除或者混淆(使用情况较少)
  • allowobfuscation允许其被混淆,但是不会被移除或者优化(使用情况较少)

class_specification规则

class_specification是类和成员的一种模板,只有符合此模板的类和成员才会被应用keep规则.

class_specification的一个复杂的示例 
这里写图片描述

[]内的内容是可选的, …表示可以有若干个前面紧邻项.

  • class可以指代任意类和接口,interface指明为接口,enum指明为枚举,在interface或enum前添加!指明为非interface或非enum.
  • classname必须用全名,例如java.lang.String.可以使用正则表达式:

    • ?表示类名中的任意单个字符,但是不包括分割符(.)
    • *表示类名中的任意多个字符,但是不包括分隔符(.)
    • **表示类名中的任意多个字符,包括分隔符(.)

    可以在类名前面添加!为取非之意.为了兼容旧版本以及使用方便,类名*表示所有类(无论其在哪个包下).

  • extends和implements关键字是等价的

  • @指明类或成员具有某些注解

由于指定成员的规则较为复杂,下面单列一节

class_specification中指定成员

成员是java样式的,但是方法参数只有参数类型而没有参数名称,成员可以有以下样式(方法没有返回值,并且只有有参数列表)

  • <init> 代表任意构造方法.
  • <fields> 代表任意域.
  • <methods> 代表任意方法.
  • * 代表任意成员(包括成员变量和方法).

成员可以使用正则表达式

  • ? 代表方法中的任意单个字符.
  • * 代表方法中的任意多个字符.

成员部分描述类型时可以使用以下通配符

  • % 表示任意基本类型(int,char等,但是不包括void).
  • ? 表示类名中的任意单个字符.
  • * 表示类名中的任意多个字符,不包括分隔符(.).
  • ** 表示类名中的任意多个字符,包括分隔符(.).
  • *** 表示任意类型.
  • ... 表示任意多个任意类型的参数.

注意?*和**无法匹配基本类型,只有***可以匹配任意维度的数组类型,例如** get*()*可以匹配java.lang.Object getObject()但是不能匹配float getFloat()也不能匹配java.lang.Object[] getObjects()

构造函数既可以通过短名字(不含包名)指定,也可以通过全名指定.

另外三个keep

  • -keepnames class_specification是-keep,allowshrinking class_specification的缩写
  • -keepclassmembernames class_specification是-keepclassmembers,allowshrinking class_specification的缩写
  • -keepclasseswithmembernames class_specification是-keepclasseswithmembers,allowshrinking class_specification的缩写

这里写图片描述

Tips

一般如果不了解应该采用哪一个keep的话就使用-keep,它可以keep住类名和成员名不被移除和修改名字 
注意:指定了keep的类而没有指定成员则只会keep类名,成员名有可能被移除或混淆

示例1

-keep class com.test.MainActivity$Item{ 
*; 

可以keep内部类(仍然为内部类),类名和成员名都没有变

示例2

keep程序入口点

-keep public class mypackage.MyMain { 
public static void main(java.lang.String[]); 
}

参考资料

  • https://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/usage.html((文中大部分内容以及图片来源于此处)
推荐到极客头条
0
0
 
 

  相关文章推荐
  •  ORACLE中的KEEP()使用方法
  •  ProGuard使用笔记
  •  Android Proguard原理及使用方法
  •  关于使用Proguard 所要注意的问题
  •  Android - 混淆jar包 ProGuard GUI 使用方法
  •  Android 中 Proguard 和JNI 相关
  •  Java混淆工具ProGuard的最简明使用方法及Warning: can’t find referenced class xxx的解决方法
  •  Proguard整理一些资料
  •  Eclipse与Android源码中ProGuard工具的使用
  •  关于ProGuard的学习了解
<iframe id="iframeu2998112_0" src="http://pos.baidu.com/gcvm?rdid=2998112&amp;dc=3&amp;di=u2998112&amp;dri=0&amp;dis=0&amp;dai=3&amp;ps=4426x563&amp;dcb=___adblockplus&amp;dtm=HTML_POST&amp;dvi=0.0&amp;dci=-1&amp;dpt=none&amp;tsr=0&amp;tpr=1498550929195&amp;ti=Proguard%E7%9A%84Keep%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95%20-%20wyzzgo%E7%9A%84%E6%8A%80%E6%9C%AF%E5%8D%9A%E5%AE%A2%20-%20%E5%8D%9A%E5%AE%A2%E9%A2%91%E9%81%93%20-%20CSDN.NET&amp;ari=2&amp;dbv=2&amp;drs=1&amp;pcs=1903x911&amp;pss=1903x4442&amp;cfv=0&amp;cpl=5&amp;chi=7&amp;cce=true&amp;cec=UTF-8&amp;tlm=1498550930&amp;rw=911&amp;ltu=http%3A%2F%2Fblog.csdn.net%2Fwyzzgo%2Farticle%2Fdetails%2F54143696&amp;ecd=1&amp;uc=1920x1040&amp;pis=-1x-1&amp;sr=1920x1080&amp;tcn=1498550930&amp;qn=35acd6475205489e&amp;tt=1498550929093.1130.1267.1269" width="960" height="90" align="center,center" vspace="0" hspace="0" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" allowtransparency="true" style="border-width: 0px; border-style: initial; vertical-align: bottom; margin: 0px; width: 960px; height: 90px;"></iframe>
原创粉丝点击