Proguard is a tool for obfuscate code for the Java platform, but also for Android, although we call it obfuscate directly, Proguard actually includes shrink, optimize, obfuscate, Preverify four steps.

  • Shrink: detects and removes unused classes, variables, methods, and attributes.
  • Optimize: code, non-entry node classes will add private, static, and final, unused arguments will be removed, and some methods will become inline code.
  • Obfuscate: Rename the names of non-entry classes, variables, and methods using short and semantic names. The name of the entry class remains the same.
  • Preverify: preverify that code complies with Java1.6 or higher specifications (the only step not related to entry classes)

Common grammar

The official manual

-keep

Protects classes and class members from compression and confusion

-keep public class com.example.MyMain { 
      public static void main(java.lang.String[]); 
}
Copy the code

Protect the MyMain class and main method

-keepclassmembers

Protects class members from compression and obfuscation when specified classes are protected

-keepclassmembers class * extends android.app.Activity {
    public void *(android.view.View);
}
Copy the code

Protect all Activty subclasses whose arguments are View methods

-keepclasswithmembers

Protects classes and class members from compression and confusion when all specified class members exist

-keepclasseswithmembers public class * { 
    public static void main(java.lang.String[]); 
} 
Copy the code

Protects all classes that contain main methods and their main methods

-keepnames

Protects classes and class members from obfuscation (only in obfuscation phase, allows compression removal, cannot be renamed)

-keepnames class * implements java.io.Serializable
Copy the code

Protects all classes that implement the Serializable interface from being renamed

-keepclassmembernames

Less used to protect a specified class member from being renamed if it is not compressed

-keepclasseswithmembernames

After compressing the code, the specified class and class members are protected from confusion if all specified class members exist

-keepclasseswithmembernames,includedescriptorclasses class * { 
    native <methods>; 
}
Copy the code

If a native method exists, protect the class and the native method from being renamed. Use includeDescriptorClasses to ensure that method parameters and return values are also not renamed

conclusion

keep From being removed or renamed From being renamed
Classes and class members -keep -keepnames
Class members only -keepclassmembers -keepclassmembernames
Classes and class members,

if class members present
-keepclasseswithmembers -keepclasseswithmembernames
  • If only the class name is specified and no class members are specified, only the class and its no-argument constructor are protected
-keep class android.support.annotation.Keep
Copy the code
  • If you specify a method, only that method is protected, and the code inside the method is still optimized

The wildcard

When specifying a class, you can use the following wildcard characters

  • The class keyword represents any class or interface

  • The interface keyword indicates only the interface

  • The enum keyword indicates the enumeration class

  • Interface and enum keywords can be added! Said in addition to… outside

  • ? Matches any character, excluding the package delimiter

  • * Matches any number of characters, excluding package delimiters

  • ** matches any number of characters, including the package separator

  • For backward compatibility, * can also represent any class, including package separators

  • The extends and implements keywords are equivalent and represent classes that inherit or implement A, but not A itself

  • The @ keyword is used to represent classes and class members decorated with the specified annotation

When specifying a member of a class, you can specify the following wildcard characters


  • matches any constructor

  • matches any member variable

  • Matches arbitrary methods
  • * Matches any member variable or method
  • The above wildcard has no return type, only

    has a list of arguments

In addition to using the omnipotent wildcard, you can also use the common expression? And * wildcard

When specifying the type of the modifier, you can use the following wildcards

  • % matches the base type
  • ? Match any character
  • * Matches any number of characters, without package delimiters
  • ** matches any number of characters, including the package separator
  • *** Matches any type (basic or non-basic, array or non-array)
  • . Matches any number of parameters of any type

? * and ** do not match base types. You can use permission controls to help match (for example, public static).

Use on the Android platform

It only needs to be configured in Gradle

release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
Copy the code

Can turn on obfuscation.

The obfuscated profile consists of three parts

A proguard – android, in the new version of the build tool, it be packaged with android gradle plugin, build/intermedates with app level/proguard files directory can be found, There is a set of obfuscation rules for all Android applications.

One is aapt_rules, generated by the aapt in packaging, in app/build/intermediates/proguard – rules / / aapt_rules. TXT can be found, The keep rule is configured for all classes used in manifest and XML;

One is ProGuard-rules.pro, which is a developer’s custom configuration rule.

The final configuration rule is a combination of these three parts, which is why confusion can be accomplished even if the developer does not define any rules.

  • The Android platform generally doesn’t require the optimize and Preverify steps because of dex.
  • With enough testing, you can turn optimize on,
  • Prevalidation is disabled in the default proGuard-Android version, and the android example on the proGuard website is also disabled. However, when testing on android Gradle version 3.1.3, The default ProGuard-Android does not remove the prevalidation line, and it is not clear why.

When using the proGuard-rules. pro file, you can copy all the configuration in the proGuard-rules. pro file to the custom configuration, understanding the functions of each rule in the default configuration, and locating problems easily.

Proguard output file

  • Dump. TXT describes the internal structure of all class files in APK.
  • Mapping.txt provides conversions between original and obfuscated class, method, and field names.
  • Seeds.txt lists classes and members that have not been obfuscated.
  • Usage.txt lists the code removed from APK.

Keep the line Numbers

- keepattributes SourceFile, LineNumberTable retains the line number informationCopy the code
- renamesourcefileattribute SourceFile to hide the name of the class file informationCopy the code

This configuration preserves the line number information in the error stack while hiding the class name, facilitating problem location

The confusion of the SDK

SDK confusion is one of the most common things that can go wrong. Many SDK developers are not aware of Proguard and do not provide users with obfuscation rules or simply provide all the rules of keep violence

There are actually two obfuscation rules for the SDK

  • One is the parts of the SDK itself that must keep, such as using reflection
  • The second is the public API, must keep to external use

Users of the SDK can choose their own rules (since not all apis use them)

It is reasonable for SDK developers to package without confusion, but to provide confusion rules to callers through consumeProguarFiles, because the rules provided by consumeProguarFiles will eventually affect the whole project, and it is better not to use wildcards in the rules. Instead, it strictly limits only what keep specifies

If the SDK developer wants to hide the internal implementation, it will be obfuscating when packaging, but it will also need to provide obfuscating rules for packaging that the consumer can choose to use.