Publish libraries including a proguard-configuration


When developing a library for Android applications, it may be essential for the library that some classes or fields are not obfuscated or removed by proguard-ing, which happens at library consumer (i.e. the application that uses the library).

But it shouldn't be the application developer's responsibility, to check yout GitHub-README page whether and which proguard-rules need to be applied to use your library.
Also, as such rules may change with further library updates, they may get outdated and never updated (like, how often do you really check the changelog when updating dependencies of your app, and how clean do you keep your proguard-rules file to keep up-to-speed with which rules were for which library?).

The consumerProguardFile

To solve this problem, the consumerProguardFiles directive, which automatically ships the given proguard-files with your library, and then are automatically merged with the applications proguard-configuration, making sure, that your libraries configuration is honored.
Within your libraries build.gradle file, define the proguard configuration file with the consumerProguardFiles command:
android {
    release {
        ...
        consumerProguardFiles 'proguard-rules.pro'
    }
}
Within the proguard-file, it is crucial to apply only the minimal set of rules the library needs, and keep anything else untouched, as the consumer of the library (i.e. the end-application) should be the one deciding about any other proguard configurations.For an internal used OAuth library I wrote, I defined the following rules ni the proguard-file defined as the consumer proguard file (the library uses OkHttp and Okio internally, why the rules of those libraries are applied as well):
##
## OkHttp
##
## (taken from https:⁄⁄github.com⁄square⁄okhttp⁄blob⁄master⁄okhttp⁄src⁄main⁄resources⁄META-INF⁄proguard⁄okhttp3.pro)
##

# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**

# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase

# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*

# OkHttp platform used only on JVM and when Conscrypt dependency is available.
-dontwarn okhttp3.internal.platform.ConscryptPlatform



##
## Okio (dependency of OkHttp)
##
## (taken from https:⁄⁄github.com⁄square⁄okio⁄blob⁄master⁄okio⁄jvm⁄src⁄main⁄resources⁄META-INF⁄proguard⁄okio.pro)

# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*


##
## library-specific rules
##

-keep class com.tailoredapps.oauth.network.model.** { *; }

The result

And that's it, just defining the proguard-file using consumerProguardFile will package the proguard-file within the libraries .aar file:
  • AndroidManifest.xml
  • classes.jar
  • proguard.txt
  • R.txt
The provided proguard.txt file will then automatically be merged with the applications proguard rules.
(Note, that the proguard configuration by default is not applied when building / shipping the library itself, but at the library-consumer when building the final application with a proguard configuration enabled.)
As a application developer, you can check the final proguard configuration (with all library proguard files merged together) using the following option within your proguard configuration, which then will print the merged configuration to the filename supplied.
-printconfiguration proguard-merged-config.txt

When including the library as a java-module

But there is still one little drawback (at the current Android Gradle plugin v3):
If you include the library as a java module within your application project (meaning, that you don't include the library using a maven server, but as a java-module present in your code-base), the consumer-proguard rule will not be honored (as there's no aar packed as when publishing the library.
To workaround that problem, you can just include the libraries proguard configuration file within your app referencing the original file (as it's present in your codebase anyways):
buildTypes {
    release {
        ...
        proguardFiles ... "$rootProject.rootDir.absolutePath⁄myLibrary⁄proguard-rules.pro"
    }
}