Better way to import library project in Android - android

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.

Related

Dependency missing but exists in APK, how?

I have a MyLocationService library, which has dependency from huawei_location_service.Inside I have HMSLocationService class which is the only one using huawei_location_service classes and I use relfection to access that class. Meaning is, if we run app on Huawei and if there is dependency from huawei_location_service, I will get location, otherwise will not. And application should run perfectly on non-hauwei devices without dependency from huawei_location_service.
So when I build MyLocationService.aar I removed huawei_location_service dependency from it's pom file. After that I created a new application and added dependency from MyLocationService.aar. When I check dependencies with command gradlew app:dependencies I don't see any dependency from huawei, but when I create an apk and analyze it, in classes.dex there are classes from huawei_location_service.
Question: How it is possible? And is there any other way to achieve what I want?
P.S. I analyzed also MyLocationService.aar, didn't find any huawei dependency. Is there another way to check dependencies of *.aar files instead of pom or analyzing tool of android studio?
So if someone will be mistaken as me, this answer will help.
The repositories and classes I saw in classes.dex were not coming from hms libraries. As I have imports in my custom classes, that imports' texts were the reason I was seeing huawei folder in classes.dex. Also take attention on the size, and you can see that they are kind of 20 bytes.
So I removed the imports, generate my library again, created apk and analyzed it and woala, no huawei folder is visible.
P.S. *.aars doesn't contain any library if you not put transitive=true. And you need to add dependencies required by your lib in your own applicaiton.
P.S.S. If you have locally or globally publishing your library, maven(Gradle uses maven) creates metadata, so called POM file, as a helper to identify all dependencies that the library needs.

Cost of importing libraries

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.

What is autovalue.shaded or what is a shaded jar?

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.

Preferable way to use dependencies in build.gradle: compile or compile file?

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'])

Android Studio Gradle External Library Project

Ok, I realize that Gradle and Android Studio seem to think that all Library Applications are built for one project and one project only, but that is not the case. I have many shared Library Applications with common purposes that are shared throughout the organization. Gradle does not seem to be very accomodating to this desired solution. Can someone offer any insight?
My current Structure at a very rudimentary level is like this:
|--Directory
| |--PROJECT A
| |---Module 1
| |--Project B
| |---Module 2
| |--Project c
| |--Module 3
/////////////////////////////////////////////
My Current dependency structure is like this:
/////////////////////////////////////////////
Project A: (FYI, Builds Just Fine)
Project A's settings.gradle
include ':Module 1', ':Module 2'
project(':Module 2').projectDir = new File('../Project B/Module 2')
Module 1's build.gradle
dependencies {
compile project(':Module 2')
}
Project C: (FYI, BROKEN)
Project C's settings.gradle
include ':Module 3', ':Module 1'
project(':Module 1').projectDir = new File('../Project A/Module 1')
Module 3's build.gradle
dependencies {
compile project(':Module 1')
}
Breaks: Cannot resolve Module 2 inside of Module 1's build.gradle file.
This is because the directory structure for Module 2 is established inside Project A's settings.gradle so Project B has no idea where to render this from.
I understand that I can add
project(':Module 2').projectDir = new File('../Project B/Module 2')
to Project C and everything will work just fine. However Project C doesn't use or know about Module 2. I want other developers to have the freedom to use my common shared library project without having to dig in and see what library projects I used and include those in their settings as well. How can I specify my own dependency directory structure in the build.gradle instead of the settings.gradle to make it accessible to all that use it?
On a second note, but similar topic. I'm having the exact same issue with JAR files. If i specify a REPO in a Library Project's build.gradle like: myRepo1 and have a myJar1. Then when that library project is used in a parent project that doesn't define the repo that contains the jar in the library projects dependeny section, it fails to resolve the jar file from the library project when compile project(':libproject') is used. I have to duplicate the repo pointers in the parent's build.gradle file as well so that the libproject will build from the parent app. Any help on this one would be appreciated as well. As not every repo is used in every app so this can become redundant.
Ok this is a really old post, but still gets traction so let me update 3 years later since I originally wrote it lol.
Shout out to CommonWare who had the right best practice idea right from the start, but didn't provide an answer to mark up.
Let me start by saying that using project references like I was doing above should be limited to development stages only and should only be if the library project is also in development stage at the same time as the main project. Otherwise a dependency management server like Nexus, Apache Archiva, or S3 with Maven directory structure or equivalent would be preferred. I have learned many ways to manage dependencies since this, including transitive dependency management.
My preferred method is to deploy artifacts with POM files to Apache Archiva and then use these dependencies within the parent project instead of using relative paths to reference code projects now. This is the first choice.
However, if you are too new to dependency management and choose not to have a server for this purpose, you may package your AAR files or JAR files and put them in one centralized repo like artifact_repo and have everyone include that repo at the same folder structure and reference them relatively, but this is not good practice so I would steer clear if you can.
You can also take the artifacts and nest them in you libs directory and bring them in that way if you would like, but it becomes more of a manual update process which some people like and others do not.
Now this opens a whole different set of issues that you need to handle.
Transitive Dependencies and Child Repo pointers.
For example, if you wrapped your own Crash Reporting Library around Fabric or Hockey or other hoping to make it easy to trade libraries later, then you have found that the repo pointer has to live in the parent build.gradle files or the transitive dependencies are not found.
You could of course use one of those hacky Fat_AAR or Fat_JAR scripts that works "sometimes" until updated gradle then they break again until someone hacks it back together, but this is also poor practice as you are creating potential mismatch dependencies on support or other important child libraries and the "exclude transitives" only works if you are using pom files to control the transitives and not making the AAR or JAR file fat. So you are limiting your ability to control the dependencies.
So what i have finally come to terms with is that transitive dependencies should be managed through POM files to allow excluding or including without nesting into children libraries. Also libraries that require repo pointers inside of them, should probably not exist as they require parent boiler plate, introduce room for human error and typically don't save much time on wrapping analytics or crash libraries for example or you start getting into json configs that need to live in parent files for PUSH or other reasons. Just avoid it.
So long story short lol. Stick to dependency management tools they way they were intended to be used and you will be fine. It is when you are new to it or start getting hacky that you run into ugly code and ugly problems. Hope this encourages someone to do it the right way :)
One last thing :). I have recently started writing Gradle Plugins to manage my versions and dependencies as a separate file so that I can use intellisense to pull in dependencies and make sure all support, gms, and tool versions are the same across all projects. You can even copy down live templates with your plugin to enable intellisense for Gradle to work with your stuff. It's not too bad to do. Best of luck and happy Gradling :).

Categories

Resources