Tuesday 1 December 2015

Gradle Dependency scopes - Lesson 2

Gradle dependency scopes for Android




A bit of history on why i chose this topic.  I ran into an issue with the android 65k limit (your code can have a max of 65k methods).  Thought of using proguard to strip unused methods but it slowed down debug builds. Developers were left waiting a long time just compile and run.  Tried multiDex and it slows down your build (at least in previous android gradle schemes).  MultiDex might work for you but i'd like to demo how we can lower method counts before having to go into that direction.

The best approach to keep the method count down would be to not even have the methods in the first place.  Don't use unnecessary methods, right ? But how ? I'll keep this as short as possible and you can get the drift and carry on.

Dependency types  


  • Provided
  • Compile
  • Package
  • Apt (for android apt plugin)

Provided:
Have you ever looked in a gradle.build file for android and seen the word provided as part of the depenencies. Like this:




This means that we only need the dependency for compilation. The end user does not need it, so drop it after we compile.  This can save us some unnecessary methods. 


Compile:
You've seen this one all the time as its the most used. It tells gradle we need this library all the time, at compile and run time.  Keep it. 

Package: 
This would be for libraries you want only when packaging. 

Apt:
As a side note, the android-apt plugin also has a scope we can use called apt. You might have seen it before when defining dagger dependencies for example. It looks like this in gradle dependencies closure:


apt 'com.google.dagger:dagger-compiler:2.0'
provided 'org.glassfish:javax.annotation:10.0-b28'

What is this apt scope ? Its very similar to provide actually. In most cases it's the same effect.  One prime difference is when you use the provided scope, the generated code is not available to the IDE. For example, let's change the dagger compiler to have a provided scope:


provided 'com.google.dagger:dagger-compiler:2.0'
provided 'org.glassfish:javax.annotation:10.0-b28'

Now if we sync gradle, the IDE will not be able to find your dagger component (ie. daggers boilerplate generated code) and you'll get an error of something like this at compile time:


error: cannot find symbol  
return DaggerMyComponent.builder() 

Using apt allows the IDE to see the generated code.

Conclusion:
If you find yourself looking for a way to minimize method calls or creating a library, have this strategy in mind at design time.  Your users will likely appreicate the consideration. 

Truth is ever to be found in simplicity, and not in the multiplicity and confusion of things. - Isaac Newton

No comments:

Post a Comment