I was looking for a way to parse a string to get an int out, and stumbled upon:
NumberUtils.toInt("blah",99);
I typed it into my IDE and it auto imported this for me:
import autovalue.shaded.org.apache.commons.lang.math.NumberUtils;
So I am curious to know, what is autovalue.shaded about and why is it 'shading' org.apache.commons?
And is it safe to use this to fulfil my need for NumberUtils?
I tried searching but I am not familiar with the assumed knowledge that search results brought up such as shaded jar and uber jar.
"Shading" is the process of embedding dependency classes within your own jar file. AutoValue does this in part to limit the transient dependencies, but also to ensure version stability of their dependencies.
You can read more about Shading here: https://maven.apache.org/plugins/maven-shade-plugin/
I would highly recommend against using the shaded dependency in your code, as it means you no longer have control of the dependency version. You can simply add the dependency directly, giving you control of when it's updated.
You might also want to check your gradle dependencies to make sure you don't have AutoValue in your compile target. I see from your other dependencies that this is an Android project, and if AutoValue is on the compile target then you're going to have a far bigger APK then you want. It should be included on the Annotation Processor classpath, via apt, so that it's classes aren't included in your final product. Hugo Visser has a nice gradle plugin for enabling the apt target for Android projects.
Related
I've been working on an Android app project. I'm using quite a few libraries (because why redo work that someone else has done to make other people's life easier?).
My question is: what are the costs of importing libraries in a project? (I'm talking about the implementation XXX.YYY:v2.0.0 type of line added in the build.gradle dependencies list.)
Just as an example (though please provide a more encompassing answer): when compiling and publishing my application, does it take all of the libraries' classes and methods and put them in my application, thus making it much heavier than it would need to be?
Each library dependency requires an additional download while you compile your app. So these will increase the amount of time required to compile.
The code for each library is included in your final APK so they will increase the size.
For Every Library a download is necessary In order to built your app.
e.g If you want Libraries regarding to Firebase then You download the Library by adding the Firebase Project to your App. In build.gradle File you see the dependencies after you add them to Your Project App.
I am working on a project and so far in order to provide minimal integration effort for my consumers, I was forced to use all core Android framework APIs. That being said, I did not use any additional dependencies although there are alot of android library available out there to make my life easier. But recently I've been thinking about using Android annotation library. and in order to use it the docs ask me to include them into the project.
dependencies { compile 'com.android.support:support-annotations:24.2.0' }
From my knowledge, this will make my consumers forced to downland the libraries(they might not need) when they use my library. Can anyone please let me know if there is any better practice to achieve that not to include the library for my consumer but only my own project scope?
UPDATED:
I think I just found those two lines from the official docs.
If you use annotations in your own library module, the annotations are included as part of the Android Archive (AAR) artifact in XML format in the annotations.zip file. Adding the support-annotations dependency does not introduce a dependency for any downstream users of your library.
But I am still curious about general dependency issue and how to handle the dependencies if we are just a library.
In general, it is OK to make the library you depend on available to the user of your library.
If several libraries require a popular dependency, it's better to have the code included just once, if you want to reduce your apk size.
Also, if the user of your library doesn't want to include the transitive dependency, an exclude option can be added to the dependency declaration.
Other case is when you hapen to provide several libraries, where you can also ensure that the transitive dependency has the same version among your libraries
In other words, I would let the users the power to decide if they want the transitive dependency or not.
I was wondering what is the recommended way of including library projects in an Android Studios gradle like this:
First way:
compile 'de.greenrobot:greendao:2.1.0'
Second way:
compile files('libs/greendao-2.0.0.jar')
and what are the pros and cons.
In the first case gradle is completely handling the process of dependency management, i.e. downloading the jar and including it in your project.
In the second case you have to manually download the jar and include it in the libs folder.
The simpler and preferred way is the first.
First way: compile 'de.greenrobot:greendao:2.1.0'
PRO:
Easy, quick to update
CON:
Internet connection required when updating your gradle file
Second way: compile files('libs/greendao-2.0.0.jar')
PRO:
You can make changes to the library and those won't be overwritten.
Like Qian Sijianhao said, it's quicker to build.
CON:
More work to set up, update
In most cases I think you want to go with the first way.
Trust me, the second way will save lots of your building time.
By the way , time is money.
In the first way, i.e:
compile 'de.greenrobot:greendao:2.1.0'
compile 'com.library.sample:library:x.x.x'
Gradle will finding these dependencies, and making them available in your build. If your dependencies have a dependencies, gradle will also finding them and include it for the project. So you don't need to manually add all the dependencies.
Quoting from Gradle documentation:
7.1. What is dependency management?
Very roughly, dependency management is made up of two pieces. Firstly,
Gradle needs to know about the things that your project needs to build
or run, in order to find them. We call these incoming files the
dependencies of the project. Secondly, Gradle needs to build and
upload the things that your project produces. We call these outgoing
files the publications of the project. Let's look at these two pieces
in more detail:
Most projects are not completely self-contained. They need files built
by other projects in order to be compiled or tested and so on. For
example, in order to use Hibernate in my project, I need to include
some Hibernate jars in the classpath when I compile my source. To run
my tests, I might also need to include some additional jars in the
test classpath, such as a particular JDBC driver or the Ehcache jars.
These incoming files form the dependencies of the project. Gradle
allows you to tell it what the dependencies of your project are, so
that it can take care of finding these dependencies, and making them
available in your build. The dependencies might need to be downloaded
from a remote Maven or Ivy repository, or located in a local
directory, or may need to be built by another project in the same
multi-project build. We call this process dependency resolution.
Note that this feature provides a major advantage over Ant. With Ant,
you only have the ability to specify absolute or relative paths to
specific jars to load. With Gradle, you simply declare the “names” of
your dependencies, and other layers determine where to get those
dependencies from. You can get similar behavior from Ant by adding
Apache Ivy, but Gradle does it better.
Often, the dependencies of a project will themselves have
dependencies. For example, Hibernate core requires several other
libraries to be present on the classpath with it runs. So, when Gradle
runs the tests for your project, it also needs to find these
dependencies and make them available. We call these transitive
dependencies.
Gradle will store the downloaded library to your USER_HOME/.gradle. In Linux, it will store it in /home/user/.gradle/caches/modules-2/. in Mac it will store it in ~/.gradle/caches/modules-2/.
By the way, if you have used the library, you can set Android Studio to use a local cache of the library.
In the second way, you need to manually add the library for your project. And you also need to include all the remaining dependencies of the library. This is so error prone.
An unreleased android library I am working on has a third party networking library in it - OkHttp in this case.
Projects that use this library as a dependency also are now able to create objects with that networking library.
Can I limit or disable access to the networking library contained within my library?
You could make the dependency transitive however if your code hits the missing code inside their app it will fail ClassNotFound or MethodNotFound
dependencies {
compile('com.squareup.okhttp3:okhttp:3.2.0') {
transitive = false
}
}
Short of that once the code is packaged with your lib it's available to anyone who wants to use it from your lib.
This still won't solve the problem as you would like but you could use proguard to rename the okhttp classes. Users of your lib could still call the okhttp classes but they would be renamed by proguard to something like a,b,c,...
What you want to do is shade the dependency. Here's a description from a blog post about shading dependencies in Gradle:
To Shade a library is to take the contents files of said library, put
them in your own jar, and change their package.This is different from
packaging which is simply shipping the libraries files in side your
own jar without relocating them to a different package. The term
fatjar is commonly used to refer to jars that have the application as
well as its dependencies packaged or shaded into them.
It's easy to do for smaller libraries. I could image it might be difficult for a large library like OkHttp. You can do it manually by simply copying the files into your project and changing the package. There are also some scripts that will do it automatically. They usually use Jar Jar Links.
Normally be default you don't have the dependencies like that:
compile rootProject.ext.okhttp
compiled in your jar only your sources are. So OkHttp classes will not be in your lib.
I have exactly the same case. I use gradle to build and upload to maven.
You can check here
So if your intention is to have the exact dept version in the package and to be hidden you just need to include it in you project as a module and to change some things like the package of OkHttp to avoid conflicts and also the access to currenly public okhttp members. OkHttp is using Okio so you may want to privatize it too.
Note that this kind of shadowing + hiding functionality of the shadowed class can be useful for framework dependencies(ensuring all depts in runtime available) but it is increasing the size of your libs and will not be the best option for apps using your lib as they anyway ensure packaging required depts in the apk.
I'm using many external libraries for my project as it saves lot of efforts by reducing the work. I prefer gradle build mechanism.
As Gradle provides following ways for adding dependencies:
Use it as external lib (I prefer when library is not available)
compile 'com.squareup.picasso:picasso:2.5.2'
By adding available jar
compile files('libs/picasso-2.5.2.jar')
What would be the best practice to use libraries in project? What are the pros and cons of using dependencies in above ways?
Consider:
Using any of these solutions does not have any influence on app performance
It's faster to copy&paste a Gradle line than to copy&paste a file
It's easier to update Gradle line when new version of the library is released. Just change few digits. You can even set it to update automagically
When it comes to Android libraries your are informed when there are updates available
Sometimes you might not have internet access and having a ready .jar file on your hard drive is win in these situations
Myself, I use Gradle whenever I can. It just makes my development process faster and easier.
Update To make my answer more complete:
Rémi Pradal had also very interesting insight in his answer:
using compile file [...] will increase a lot the size of your repository as you will probably commit the .jar files.
Application performance is not dependent on which method you use for dependency management. Dependency management is for making developer's life easier.
Consider this, new version of a particular library got released with few additional features and you want to migrate to the newer version. If you are using the second method, you will have to remove existing jar file and download new version's jar file and include it in your codebase. But, if you are using the first method, it's just a matter of changing the version.
In conclusion, If the library or jar available in Maven (or any global repository), use the first method. If jar is only available as a direct download, we don't have any other option, go for second method.
Also, for the second option, you can add all jar files to the project in one single line, like this:
compile fileTree(dir: 'libs', include: ['*.jar'])