if (ConfigurationConstants.AT_DIRECTIVE.startsWith(nextWord) |
在调用parseIncludeArgument的时候会往wordReader里面设置一个内置对象:
if (ConfigurationConstants.BASE_DIRECTORY_DIRECTIVE |
if (ConfigurationConstants.KEEP_OPTION.startsWith(nextWord)) |
private List parseKeepClassSpecificationArguments( if (!ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD readNextWord("keyword '" if (ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION // Read the class configuration. // Create and add the keep configuration. |
这些是你的指令,而你的数据是定义在ClassSpecification。我们按照流程下来看的话,其实阅读这些代码并不费劲,可见我们在包装完这种类的keep之后我们需要开始解析类数据。这种流程是面向过程的一种过程。这样不知道各位是不是更好理解.其实我为何愿意看Proguard的源码呢?因为它的代码结构很简单,每个函数很少有超过200行代码的。虽然一个类的代码挺长,但是代码结构都是一种模式.看起来还是颇为惬意的一件事。(你可以试试Android的AMS源码~泪奔)
public ClassSpecification parseClassSpecificationArguments() // Clear the class access modifiers. // Parse the class annotations and access modifiers until the class String strippedWord = negated ? nextWord.substring(1) : nextWord; // Parse the class access modifiers. // Is it an annotation modifier? // Is the next word actually an annotation type? // Continue parsing the access modifier that we just read // Otherwise just handle the annotation modifier. if (!negated) { if ((requiredSetClassAccessFlags & requiredUnsetClassAccessFlags) != 0) { if (strippedWord.equals(ClassConstants.EXTERNAL_ACC_INTERFACE) // Should we read the next word? // Parse the class name part. // For backward compatibility, allow a single "*" wildcard to match any // Clear the annotation type and the class name of the extends part. if (!configurationEnd()) { // Parse the annotation type, if any. String externalExtendsClassName = ListUtil extendsClassName = ConfigurationConstants.ANY_CLASS_KEYWORD // !new class meta // Now add any class members to this class specification. // Parse all class members. if (nextWord.equals(ConfigurationConstants.CLOSE_KEYWORD)) { break; parseMemberSpecificationArguments(externalClassName, return classSpecification; |
这种具体的类,或者是@class @interface @anum都是可以的,而对于@class @interface @anum
的处理逻辑都是一样的,简单一点就是跳过(紫色代码段)。我们看到中间部分的绿色部分代码,这个时候 keep ![public,private,protected][class interface @anno anum] name就解析完成。 实际上这个已经是一个完整的keep配置了(类似-keep class com.test.Class2);这里提一下,每个配置项的结束是通过@符号或者-符号作为标志的。我们可以在classname之后再增加implement和extends这类的关键字,Proguard还是一如既往的不做区分。好了到了这一部,我们足够数据定义一个完整的类的元数据。接下来就是蓝色部分的参数解析;抛开一些无关紧要的代码我们直接看重点:
private void parseMemberSpecificationArguments(String externalClassName, // Parse the class member access modifiers, if any. while (!configurationEnd(true)) { String strippedWord = nextWord.startsWith("!") ? nextWord // Parse the class member access modifiers. if (strippedWord.equals(nextWord)) { // Make sure the user doesn't try to set and unset the same readNextWord("class member description"); // Parse the class member type and name part. // Did we get a special wildcard? classSpecification.addField(new MemberSpecification( classSpecification.addField(new MemberSpecification( classSpecification.addMethod(new MemberSpecification( // We still have to read the closing separator. if (!ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)) { readNextWord("class member name"); // Did we get just one word before the opening parenthesis? // Assign the fixed constructor type and name. // Read the opening parenthesis or the separating // Are we looking at a field, a method, or something else? // We already have a field descriptor. // Add the field. // Parse the method arguments. if (!ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD // Read the separator after the closing parenthesis. if (!ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord)) { // Add the method. |
public static final String ANY_CLASS_MEMBER_KEYWORD = "*";
public static final String ANY_FIELD_KEYWORD = "<fields>";
public static final String ANY_METHOD_KEYWORD = "<methods>";
可以看到实际上就是比类定义的数据结构多了属性的任意匹配和方法匹配,其实还多了属性的修饰符。比如private final 注解这一类,除了比较传统的public static private protected 这种的关键字说明意外,还增加了“!”用来表示非的逻辑关系。这里要特别说明的一点是由于作用域和static说明是采用位标志的方式存在,因此可以不在意顺序但是!一定要放在条件的开头部分。而且在属性定义中,也支持了分号为结尾的定义方式。红色代码部分是不采用通配符的方式来定义方法或者属性说明,我们看到,对于方法而言,Proguard将为其生成一个方法的描述符号,用来唯一标识该方法。
待续。。。
--非子墨