Reputation: 4272
I'm trying to make a conditional build in Android Studio, where I can reduce the size of the generated APK by removing any superfluous library dependencies if they're not needed for a particular distribution.
I've got some code which roughly approximates to the following:
public class MyClass {
/* Static Declarations. */
public static final boolean USE_LIBRARY = false;
public void doSomething() {
// Are we using the library?
if(MyClass.USE_LIBRARY) {
// Do something with the library that we'd define in my build.gradle.
com.some.gradle.library.MyLibrary.doSomethingWithLibrary();
}
else {
// Do something else.
}
}
}
If I remove com.some.gradle.library
from my Gradle dependencies, I receive compilation errors indicating that the above code cannot be compiled. As you can see, provided that USE_LIBRARY
remains false, we should never need to make any reference MyLibrary
; not even upon instantiation, as it makes no reference to the imports; these are only encroached upon at runtime.
I should probably note that in practice, USE_LIBRARY
is a programmatically generated constant pertaining to the app's BuildConfig.java
.
Surely the compiler can determine that this code can be optimized? Is this some kind of pre-processor check that I can work around?
Upvotes: 0
Views: 1941
Reputation: 4272
Found the solution. The above approach I've taken is possible, provided that you can guarantee that no library code may be interacted with at runtime; this includes making sure that none of your runtime classes extend
any parents or implement
interfaces that are a part of the library. I was able to verify that the code had been expunged by using ClassyShark.
The "trick" is to declare the library components as provided
for the build variant where you want to pretend the libraries are available to you, and as compile
for when you wish to export the libraries.
i.e. Use two Build Variants, libraryVariant
and emptyVariant
, which programmatically switch the value of USE_LIBRARY
via buildConfigField 'boolean', 'USE_LIBRARY', 'X'
. Then you may define your dependencies as follows:
dependencies {
// Actually package the library with the compiled APK.
libraryVariantCompile "com.some.gradle.library:-1"
// Ignore the library; just please the linting process.
emptyVariantProvided "com.some.gradle.library:-1"
}
Upvotes: 1
Reputation: 3451
I think you might be confusing the behavior of the Java runtime and compile time processes.
During runtime, your code can be conditionally executed and a library call can be ignored, but during compile time all the code is processed.
By referencing the library at compile time, the dependency is required at compile time.
However, there is a utility called Proguard that is part of the android build system which can remove unused byte code from the apk. Also, check @CommonsWare answer, if you aren't using the library at all in a different version then build types allow you to create a separate version of the apk without that library
Upvotes: 1
Reputation: 1007574
I'm trying to make a conditional build in Android Studio, where I can reduce the size of the generated APK by removing any superfluous library dependencies if they're not needed for a particular distribution.
Step #1: Define a product flavor for that "particular distribution". For the purposes of this answer, I will call this foo
. You will also need other product flavors for other distributions.
Step #2: Change your compile
statement that pulls in this JAR to a fooCompile
statement, so it will only be used on foo
builds.
Step #3: Have one edition of MyClass
in each of the product flavors' source sets (e.g., src/foo/java/
), where the one in foo
references the library, and the others do not.
Upvotes: 2