Recently, the library of the company project needs to be released to the third party, so the problem of code security was exposed. Previously, it was handled by other Android teams inside, but the way to deal with it was very violent, which was to directly not confuse our library project, so that the code was easily decompiled. I had to force a wave.

This article records how to do android Libray project obfuscation experience. Android is definitely confused with ProGuard, so let’s get started.

1. ProGuard basis

1.1 Basic ProGuard Configuration

There are plenty of articles on obfuscation learning on the web, and HERE I’ve compiled some basic configuration options

# Specify the compression level of the code. The value is between 0 and 7. Optimizationpasses 5 # Print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes 5 # print obliquity passes To make decomcompiling more difficult, you can choose not to compress -dontshrink # Preserves the name and method of the argument. This option preserves debug-level properties. - keepParameterNames # Filters generics, enabling this only when conversion errors occur. The current project has no generic types for the time being, - KeepAttributes *Annotation* # specifies not to ignore members of classes that are not public libraries - dontskipnonpubliclibraryclassmembers # specify not to ignore the public library classes (don't jump the non public class library) - dontskipnonpubliclibraryclassesCopy the code

If there is an unreasonable or better option remember to tell me yo 😄 thank you very much

1.2 Proguard keywords about Keep

The keyword describe
keep Preserves classes and members of classes to prevent confusion or removal
keepnames Preserves classes and members of classes to prevent confusion, and members that are not referenced are removed
keepclassmembers Keep only members of the class to prevent confusion or removal
keepclassmembernames Only members of the class are retained to prevent confusion, and members without references are removed
keepclasseswithmembers Preserves classes and members of classes, preventing confusion or removal, and preserves specified members
keepclasseswithmembernames Retain classes and members of classes to prevent confusion, retain specified members, and remove members that do not have references

The first keyword worth noting here is keep

If you want to keep the name of the class, you can configure it as follows:

# the following configuration only retained the MyClass class name, all the members of the class will still be confused - keep class. Com. Your class. The name. The MyClass # only specify your class members matching rules can make effective confusing rules inside the body. -keep class com.your.class.name.MyClass {*; } # for 🌰 the following configuration is that I used to handle class library project, expected to open out all public methods, do not want to be mixed configuration - keep class. Com. Your class. The name. MyClass {public < fields >; public <methods>; public static final <fields>; }Copy the code

1.3 Proguard Wildcard

The wildcard describe
<field> Matches all fields in the class
<method> Matches all methods in a class
<init> Matches all constructors in a class
* Matches characters of any length, excluding package name delimiters (.)
支那 Matches characters of any length, including the package name delimiter (.)
* * * Matches any parameter type
. other

1.4 Android unique @keep tag

By default, @keep is still confused because Android Studio does not enable this option by default. Add the following configuration to the confused configuration file proguard-rules.pro:

-keep class android.support.annotation.Keep -keep @android.support.annotation.Keep class * -keepclasseswithmembers class  * { @android.support.annotation.Keep <methods>; } -keepclasseswithmembers class * { @android.support.annotation.Keep <fields>; } -keepclasseswithmembers class * { @android.support.annotation.Keep <init>(...) ; }Copy the code

⚠️ Note: at present, some information on the Internet shows that if @keep is added to a class, only the name of the class is logically not confused, but from the practical results, if @keep is added to the name of the class, the whole class cannot be confused.

1.5 Preserve Native methods

Theoretically, JNI layer-related methods should not be confused and removed directly even if they are not called, otherwise, registration failure will occur when JNI methods in registration mode are used in NDK.

-keepclasseswithmembers class * {
    native <methods>;
}
Copy the code

In combination with the Keep keyword description, the above configuration can preserve the class and the named native method member functions in the class.

1.6 Preserve the UI-related classes of the Library project

The re-wrapped library project inevitably has some UI-related utility classes, and if this part is confused, the introduction will become unusable. We need to have non-confusing control over this part as well.

-keep public 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 -keepclassmembers class * extends android.app.Activity{ public void *(android.view.View); } -keep public 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); } # keep class **.R$* {*; }Copy the code

2. Enable obfuscation

This is not enabled by default in the Android Studio configuration and we need to manually enable it.

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

But this only works after every Release package, and we sometimes need to do obfuscation testing at Debug, where we can add a new buildType

android {
		...
    buildTypes {
        release {
            minifyEnabled true // open ProGuard
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debugMini {
            initWith debug
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            matchingFallbacks = ['debug']}}}Copy the code

So we can choose buildVariants when the default Run we just new debugMini specified.

3. Summary

This short article should help many partners out of the pit, but more use or need to accumulate in the work. Some small experience eat all the obfuscation configuration without asking for a obfuscation command. We need fine configuration, and there are always some unpleasant things in general configuration. So let’s conduct one-to-one configuration for a single Class, and I believe we can get better obfuscation results.

That’s about it for this time. Welcome to leave a comment and discuss learning and progress together.

Thank you.