preface

Confused recently in finishing the project, on a lot of pit, if you don’t open the confusion, project launched is streaking, risk is very big and confusing if you open the processes is not good, there will be a lot of puzzling problem, so I put together a comprehensive code mixed method, including componentization and confused the SDK code scheme, more practical, hope to help everyone.

Open the confusion

Open the build.gradle file in app module and set minifyEnabled to true

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

Proguard-android. TXT is the default obturation configuration file provided by Android. In the configured Android SDK /tools/ proGuard directory, you can open it to see if you are interested. Proguard-rules.pro is our custom obfuscation profile where we can put our custom obfuscation rules.

Custom obfuscation rules

Confusing common commands

The command Introduction to the
dontwarn Dontwarn and Keep are often used together, especially when introduced to the Library, to ignore the library warnings and keep builds going
keep Preserves classes and members of classes, preventing renaming or removal
keepnames Preserves classes and their members from being renamed. Members that are not referenced are removed
keepclassmembers Only members of the class are retained, preventing renaming or removal
keepclassmembernames Only members of the class are retained to prevent renaming. Members without references are removed
keepclasseswithmembers Preserves classes and members that own the member, preventing renaming or removal
keepclasseswithmembernames Preserves classes and members that own the member, preventing renaming

Keep the rules of

[keep command] [class] {[member]}Copy the code
  • “Class” represents a class-related qualification that will eventually locate some classes that meet that qualification. Its contents can be used:
    • Concrete classes
    • Access modifiers (public, protected, private)
    • Wildcard *, matches any length of character, but does not contain the package name delimiter (.)
    • The wildcard character ** matches characters of any length and contains the package name delimiter (.)
    • Extends, which is the base class of a class that you can specify
    • Implement, matches a class that implements an interface
    • $, inner class
  • “Member” represents a qualification associated with a class member, which will eventually locate some class member that meets that qualification. Its contents can be used:
    • Matches all constructors
    • Match all domains
    • Match all methods
    • Wildcard *, matches any length of character, but does not contain the package name delimiter (.)
    • The wildcard character ** matches characters of any length and contains the package name delimiter (.)
    • The wildcard character *** matches any parameter type
    • … Matches any type of argument of any length. Such as void test (…). I can match any void test(String a) or void test(int A, String b).
    • Access modifiers (public, protected, private)

Common confusion rules

# Turn off bugly SDK warning -dontwarn com.tencent. Bugly.** # Don't confuse a class -keeppublic class com.jesse.example.Test {*; } # do not confuse subclasses of a class -keeppublic class * extends com.jesse.example.Test {*; } # do not confuse all classes of a package -keepclass com.jesse.example.bean. * *{*; } # do not confuse all classes whose class names contain "model" and their members -keeppublic class* * *model*. * *{*; } # do not confuse the implementation of an interface -keepclass * implements com.jesse.example.TestInterface {*; } # do not confuse the constructor of a class - keepClassMembersclass com.jesse.example.Test {
    public<init>(); } # do not confuse a specific method of a class - keepClassMembersclass com.jesse.example.Test {
    public void test(java.lang.String); } # do not confuse the inner classes of a class -keepclass com.jesse.example.Test$* {*; }Copy the code

For more proGuard rules, go to the official website

Componentized code obfuscation scheme

When you create an Android Module, the build.gradle of the Module automatically generates two proGuard configurations as follows:

defaultConfig {
    ...
    consumerProguardFiles 'consumer-rules.pro'
}

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

As for the difference between consumerProguardFiles and proguardFiles, I checked on the Internet, and none of them said clearly. Seeking others is better than seeking oneself. After my practice, I summarized the following differences, and those who are interested can also practice by themselves to see if I am right:

  • consumerProguardFilesThe configured ProGuard is plugged into the AAR, andproguardFilesConfigured ProGuard will not be tapped into an AAR
  • proguardFilesThe configured ProGuard file only applies to library code, only when compiling and publishing an AAR, after you have added the library as a module to the App moduleconsumerProguardFilesThe configured ProGuard file will be appended to the PROGuard configuration file of the APP module, acting on the entire APP code.

With their differences understood, let’s look at the componentized code obfuscation scheme.

Scheme 1: Manage all obfuscation rules in the APP module

Advantages: All obturation rules are managed uniformly in proguard-rule-pro file of app module

Disadvantages: After removing some modules, you need to manually remove the obfuscation rules in the APP module. In theory, adding too many obfuscate rules will not cause crashes or compilation failures, but will affect compilation efficiency

Scheme 2: Component Modules manage their own obfuscation rules

Advantages: Obfuscation files are decoupled to each module without affecting compilation efficiency

So how do we decouple? We can use consumerProguardFiles to configure the confusion rules in each component module, because the confusion rules configured in this way will eventually be appended to the confusion rules in the APP module, and finally unified confusion.

Componentized code confusion summary

We can place fixed third-party obliquities in the common module’s consumer-rules.pro file, and each module’s unique third-party reference library obliquities in its own consumer-rules.pro file. In the proGuard-rule-pro file of the APP module, put the general obfuge declaration of Android, such as the four major components and global obfuge configuration. In this way, the confused-decoupling operation can be completed to the maximum extent.

SDK code obfuscation scheme

The obfuscation scheme of SDK code is roughly the same as that of componentized obfuscation scheme. SDK code generally goes through two obfuscation processes:

SDK internal confusion

It is mainly to confuse the relevant core code, keep exposed classes, and write confused configuration files in the proguardFiles configuration file.

External confusion

When external rely on our SDK, after the obfuscation is enabled, the classes inside the SDK will also be confused, which may result in the reflection call ClassNotFoundException exception, so we need to keep these classes that need to be reflected. These obtainable configurations need to be written in the consumerProguardFiles configuration file inside the SDK, The consumerProguardFiles configured by the consumerProguardFiles will be appended to the ProGuard configuration file of the APP module, acting on the entire APP code.

Special note: We often use dependencies like compileOnly when developing SDKS to reference the SDK, inside the SDKconsumerProguardFilesThe configured ProGuard will also be introduced

Finally, the confusing configuration common in the app is attached

# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- basic instruction area -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # specified code compression level0 - 7Specifies the number of times the code should be iterated, which is the default in Android5This directive also works only if it can be optimized. -optimizationpasses5# confusion when won't produce all kinds of class name (confusion when not using mixed case class name) - dontusemixedcaseclassnames # specify not to ignore the public library classes (don't skip of the librarypublicClass) - dontskipnonpubliclibraryclasses # specified not to ignore the members of the public library class - dontskipnonpubliclibraryclassmembers # No prevalidation, not required by Android, can speed up the obfuscation. -dontpreVerify # log when obfuscated (print details of obfuscated) # this sentence can make our project obfuscated generate mapping file # contain the class name -> obfuscated class name mapping -verbose -printmapping Proguardmapping.txt # to specify the algorithm to be used for obfuscation, the following parameter is a filter. code/simplification/cast,! field/ *! class/merging/*Copy the code
Keepattributes *Annotation*,InnerClasses -ignorewarnings # avoid confusing generics, which is very important when mapping JSON entities, For example, fastjson-keepAttributes Signature # keeps the code line number when throwing an exception, In abnormal analysis can convenient location - keepattributes SourceFile, LineNumberTable # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the default reserves -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- keeppublic class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
-keep class android.support. * *{*; } # keep all localnativeMethod is not be confused - keepclasseswithmembernamesclass * {
    native<methods>; } # keep method parameters in the Activity as view methods, # so that we can write onClick inside layout without being affected - keepClassMembersclass * extends android.app.Activity{
    public void*(android.view.View); } # Enumeration classes cannot be confused - keepClassMembersenum * {
    public static **[] values();
    public static** valueOf(java.lang.String); } # keep custom controls (inherited from View) from being confused -keeppublic class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int); } # keep Parcelable serialized classes from being confused -keepclass * implements android.os.Parcelable {*; } # keep Serializable classes from being obfuscated -keepclass * implements java.io.Serializable { *;}
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace(a);
    java.lang.Object readResolve(a); } # For all classes and methods under R (resource), do not confuse -keepclass* *.R$* {*; } # Do not confuse keepclassmembers with onXXEventclass * {
    void *(**On*Event);
}

-keepclassmembers class * {
   public <init>(org.json.JSONObject);
}

-keepattributes *JavascriptInterface*

#----------------------------------------------------------------------------

#---------------------------------webview------------------------------------
-keepclassmembers class fqcn.of.javascript.interface.for.Webview {
   public *;
}
-keepclassmembers class * extends android.webkit.WebViewClient {
    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
    public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
    public void *(android.webkit.WebView, jav.lang.String);
}
Copy the code