// In ProGuardTask @TaskAction publicvoidproguard()throws ParseException, IOException { ... // Run ProGuard with the collected configuration. new ProGuard(getConfiguration()).execute(); }
就如我們前面Part1提到的,ProGuard第一步是讀取ProGuard設定。
Read Configuration
首先看到getConfiguration():
// In ProGuardTask private Configuration getConfiguration()throws IOException, ParseException { ...
// In Configuration /** * A list of {@link KeepClassSpecification} instances, whose class names and * class member names are to be kept from shrinking, optimization, and/or * obfuscation. */ public List keep;
// In ConfigurationParser public ClassSpecification parseClassSpecificationArguments()throws ParseException, IOException { ... // Parse the class annotations and access modifiers until the class keyword. while (!ConfigurationConstants.CLASS_KEYWORD.equals(nextWord)) { ... } // Parse the class name part. String externalClassName = ListUtil.commaSeparatedString(parseCommaSeparatedList(...);
// For backward compatibility, allow a single "*" wildcard to match any // class. String className = ConfigurationConstants.ANY_CLASS_KEYWORD.equals(externalClassName)? null : ClassUtil.internalClassName(externalClassName);
// Clear the annotation type and the class name of the extends part. String extendsAnnotationType = null; String extendsClassName = null;
if (!configurationEnd()) { // Parse 'implements ...' or 'extends ...' part, if any. if (ConfigurationConstants.IMPLEMENTS_KEYWORD.equals(nextWord) || ConfigurationConstants.EXTENDS_KEYWORD.equals(nextWord)) { readNextWord("class name or interface name", ...); ... String externalExtendsClassName = ListUtil.commaSeparatedString( parseCommaSeparatedList("class name or interface name", ...));
// Create the basic class specification. ClassSpecification classSpecification = new ClassSpecification(lastComments, requiredSetClassAccessFlags, requiredUnsetClassAccessFlags, annotationType, className, extendsAnnotationType, extendsClassName);
回到parseClassSpecificationArguments(),接著還有:
// Now add any class members to this class specification. if (!configurationEnd()) { // Check the class member opening part. if (!ConfigurationConstants.OPEN_KEYWORD.equals(nextWord)) { thrownew ParseException("Expecting opening '" + ConfigurationConstants.OPEN_KEYWORD + "' at " + reader.locationDescription()); }
// In WordReader public String nextWord(boolean isFileName, boolean expectSingleFile)throws IOException { currentWord = null; ... // Get a word from this reader. // 1 ============================== // Skip any whitespace and comments left on the current line. if (currentLine != null) { // Skip any leading whitespace. ... currentIndex++; ... // Skip any comments. ... }
// 2 ============================== // Make sure we have a non-blank line. while (currentLine == null || currentIndex == currentLineLength) { currentLine = nextLine(); if (currentLine == null) { returnnull; }
currentLineLength = currentLine.length();
// Skip any leading whitespace. currentIndex = 0; ... // Skip the comments. ... }
// 3 ============================== // Find the word starting at the current index. int startIndex = currentIndex; int endIndex;
char startChar = currentLine.charAt(startIndex); if (isQuote(startChar)) { ... } elseif (isFileName && !isOption(startChar)) { ... } elseif (isDelimiter(startChar)) { ... } else { // The next word is a simple character string. // Find the end of the line, the first delimiter, or the first // white space. while (currentIndex < currentLineLength) { char currentCharacter = currentLine.charAt(currentIndex); if (isNonStartDelimiter(currentCharacter) || Character.isWhitespace(currentCharacter) || isComment(currentCharacter)) { break; } currentIndex++; } endIndex = currentIndex; }
// Remember and return the parsed word. currentWord = currentLine.substring(startIndex, endIndex);
while (true) { if (checkJavaIdentifiers) { checkJavaIdentifier("java type", allowGenerics); } ... list.add(nextWord); ... else { // Read a comma (or a different word). readNextWord(); }