How can I access Activity from AAR library which is not directly included into the project but is embed to another AAR library?
I got an error java.lang.NoClassDefFoundError: Failed resolution of:
The class is public and if I compile it directly in project application it can be used without problem.
I included an AAR to my project like this :
ProjectApplication
|
+--sharedModule (android library - AAR or any working solution)
| |
| +--Module1 (android library - AAR or any working solution)
| |
| +--Module2 (android library - AAR or any working solution)
| |
| +--Module3 (android library - AAR or any working solution)
compile (project(":sharedFrameWork")){ transitive = true }
which has also included in itself 2 other AAR libs. They are also set to be Transitive. When I try to open an activity from one of the sub AAR libraries. I got the class not found error. But when I include that particular AAR into my application directly the class is found and can be used. It looks like I do not have access to any sub AAR libraries which are not included directly into my Application.
To better describe my situation :
I have to create an integration AAR library (later called 'sharedFrameWork') which includes multiple AAR libraries and is later embed into an application.
Multiple AAR -> Shared AAR 'sharedFrameWork' -> Application
The sharedFrameWork has some method which starts some activities from the included AAR's or set up basic communication with the server. I have read that if all the dependencies are set to be transitive it will make it work, but unfortunately it does not.
So When I call from my application a method which should start an activity from one of the included AAR in sharedFrameWork the app reports me that no such a class was found.
But when I include that AAR module right to my application not to sharedFrameWork, and then call the exact same functionality the Class is found and the project is working as it is designed. Can you help me how can I create this sharedFrameWork to be working as it is designed? Can it be done by using AAR or should I take another approach? If any other way it can be done and the result will be that I can deliver just one library and it will work as designed so it can access its submodules I will go with it, feel free to point me out the best approach for this problem.
If I get it right, you want to create a fat AAR and achieve a single import of several libraries.
Now, since you haven't provided more info, I'm going to assume you are using gradle 2. In gradle 2, submodules don't share their dependencies. neither does anything you put into the libs folder. So, first, I would upgrade your projects to gradle 3, switch from "compile" command to "api" command, and check.
If that does not work, the next step would be to apply the gradle maven plugin to each one of your modules, and deploy the resultant AAR file to either your local maven repo (automatically created when you install maven), or a remote repo, like jitpack. If you have AARs/JARs into the libs folder, deploy them to a repo too and import them from there (libs folder scope is local in gradle 2, and in general, is a bad idea to use it instead of a centralized repo. You can even use github as a repo). Then, use the artifacts.
Finally, the last solution for your problem would be to use "shading"; the process to pack several different artifacts into one. If you can't upgrade to gradle 3, or deploy the artifacts somewhere (unlikely), this is what you should do. There are several plugins for this:
https://plugins.gradle.org/search?term=shade
https://github.com/zawn/android-shade-plugin
if those don't work for you, switch to maven and use the maven shade plugin.
As a side note, you should not provide a fat AAR. Is better to keep your framework in separate modules. That will speed up your build process and allow you to save space if you don't require some classes. Even in a multimodule project, you can create separate artifacts, one for each module, and import them as you need. Just avoid circular references (a module A that requires a module B which requires module C which requires module A) and you'll be fine.
Related
I am working to build an SDK that can be used in other application.
My project structure is as follows:
ProjectFolder
|
+--AndroidLibs
| |
| +--UI (android library - AAR)
| |
| +--Protocol (android library - AAR)
| |
| +--infra (android library - AAR)
|
+--SDK(depends on UI, Protocol and Infra)
|
+--APP(depends on SDK)
As you can see, we have 3 different libraries that we work on, each one is a module in our system (infra, ui and protocol). Each one of them is creating an AAR.
Our SDK is a wrapper with some API calls to the lower layers.
We want to create one AAR that depends on all other AARs, but from some reason when we tried to run it, it says that he can't find the source code for some classes.
I found some questions related to this issue, but they didn't worked.
Also tried to work with transitive dependencies, but the bottom line is the same - can't find the source code.
android-studio-how-to-package-single-aar-from-multiple-library-projects: One answer that says there no solution for that (Google employee).
create-an-aar-with-multiple-aars-jars: use the transitive dependencies.
Create Mojo for creating AAR with all "aar" dependencies
Is there anything else we can do?
From my answer here:
As far as I know you cannot include aars inside an aar. They don't have configuration files that state what dependencies they need. You can either
Strip the source code from the libraries you are using and compile it with your aar. This will do the job if the UI/Protocal/Infra libraries are in-house and you are the only provider.
Consider uploading to bintray or Maven Central Repository
Number two is more preferable since this way all your client has to do is to include a link such as compile 'com.abc.efg:version' to grab all the dependencies you configured. It is also a much better option because there are ways of dealing with version conflicts (ex. with exclude group).
Imagine if your client was using another sdk which was pulling in a different version of UI/Protocal/Infra. If your aar was given to them via the first method, they won't even be able to build the project at all due to version conflicts. However with the second version, they can simply do
compile ('com.abc.efg:version') { exclude group: 'com.companyName.ui' }
and be free from all that headache. A real life example is Facebook's SDK. It pulls in google's play-services, but people often already include that as a dependency for their project and run into problems like this.
As your projects generally relies on both internal and third-party libraries. The internal libraries can be published on Artifactory repositories and resolve the dependencies over Artifactory with Gradle.
Its easy! Just go through the below articles,
http://jeroenmols.com/blog/2015/08/06/artifactory/
https://inthecheesefactory.com/blog/how-to-setup-private-maven-repository/en
This is highly scalable and its easy to maintain your code across multiple modules.
Hope this would help you!
I try to have 2 independent projects in AndroidStudio :
/some_root/Lib1
/some_root/Project1 ('app')
The build lifecycle of the 2 projects are separated (2 gits, 2 jenkins target, ...) and Lib1 is used by some other projects.
When I build Lib1, I want to generate a versioned aar.
When I build Project1, that depends on Lib1, I want to generate an apk WITHOUT rebuilding my lib each time (aar installed on local maven or nexus).
I would love to be able to see/edit/refactor my local library files next to my Project1 (if it have the required snapshot version in gradle dependency) from AndroidStudio.
And in the same time, I need to be able to reproduce this setup on some other projects (eg Project2) and switch easily from one to the other.
Is it event possible?
Note: I have tried some configurations in settings.gradle to load a project from another URL but it implies dependency build each time, and it's not possible for me. I have also failed to use AS dependency system (I suppose it use gradle each time so it's not viable too).
I have started working on a project where I will need to share a bunch of Java classes across a bunch of apps. In Eclipse it was possible to create one project with all such classes and use it as a library in a workspace with all your dependent projects, but in Android Studio it doesn't seem possible to do so (At least not easily).
I have been reading a bunch of posts and a lot of them suggest setting up a library project, generating an aar file and then using that in my projects. But, as I understand it, this will make my library open-source (Am I right?), which I don't want. I am doing this for a client and I want the code base to be private.
Also, I know that a module can be imported into a new project. But this creates a COPY of the original module. This is not what I want at all. I don't wanna maintain multiple copies of the same classes, which completely defeats the purpose of 'code sharing'.
Is there any good way of achieving what I am looking for? Any help is appreciated.
You have a couple different options.
One option is to maintain your libraries as separate projects and compile them to an archive format, such as JAR or AAR; JAR files are for pure Java libraries, and AAR is for Android libraries (which contain code that accesses Android APIs and/or has Android resources). As was pointed out in the comments, AAR doesn't force you to publish your code to the world any more than JAR files would; it's just an archive file format whose files can be local to your machine or your organization.
With that archive file in hand, you can include it in other projects. If you're part of a multi-developer organization, you may find it convenient to use a repository manager to publish and maintain those libraries within your organization, and you can use Maven coordinate-style specs to include libraries in your projects, which you don't have to manually copy over to your development machine.
The disadvantage of this approach is that it makes it a little harder to make changes to those libraries: you need to load up the project, make changes, build an archive, and distribute the archive.
The other approach is to keep the library as a source module like you did in Eclipse. You observed that Android Studio will make a copy of the module if you import it via UI, but if you bypass the UI and modify the build scripts directly, you can do what you want, which is to use the module in-place and share a single copy among multiple projects. To do this, work in your settings.gradle file and add this:
include ':module_name'
project(':module_name').projectDir = new File(settingsDir, '../relative/path/to/module')
I would strongly encourage you to not use a pure relative path here; in this example, the path is anchored to the settingsDir variable supplied by Gradle, which is defined to be the directory where settings.gradle is found. If you use a pure relative path (i.e isn't anchored to anything), you're dependent on the working directory being the same in all environments where the build file is run (command line vs. Android Studio vs. CI server), which isn't a good thing to assume.
You need to think in the eclipse projects as Android Studio/IntelliJ Idea modules. Then, you can generate android (or java) libraries and then include them in your project.
To mark an Android Studio module as a library you can go to File -> Project Structure -> Facets and there click on Library Module
I was in same situation as you, and i founded an approach using git.
Steps to do, to have library:
Create project in Android Studio.
Create android library module in that project.
In that library module create git repository.
Add modulename.iml in .gitignore file
Use GitHub or Bitbucket for private cloud repository. and push your library to it.
Create new android library model in any project that you want.
Close Android Studio (not sure is that mandatory).
Using explorer go to your created module folder.
Remove all data in it, except modulename.iml.
Clone your library from "GitHub" into it.
That's all.
Now you are able to use library in multiple project whether you are at home or at work. Just after finishing you work not forget to push library changes. And after opening new one pull them.
I think you can automate this thing somehow.
The benefit is that you don't need to build any jar, or aar.
You can certainly create and use a library without making it open source or available to others.
First, you don't need to make it an aar unless it contains Resources.
If it's just plain classes, you can just make it a .jar file.
Either way, the easiest way to share these libraries (either aar or jar) is to set up your own repository. Nexus and Artifactory are the two most common repository managers.
You keep the library in its own project, and then publish it to your own, in-house repository.
Then, projects that need to use the library are configured (in gradle) to use the in-house repository, and get the library from it.
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 :).
I have maybe this not so common setup:
(> = dependency)
Android project > Android library project 1 > Android library project 2
So I have an Android library project which has a dependency to another library project.
When I'm building project in Eclipse everythings works fine but I cannot get my build working with Ant.
First Ant compiles Android library project 2 which generates a classes.jar and puts this file in the bin folder.
Then Ant tries to compile the Android library project 1 but then I'm getting errors becouse it is missing classes from Android library project 2.
Well this is not so weird becouse the jar file is not included in the libs folders.
But in project.properties i've made a dependency to the library project 2 so why does Ant not copy the classes.jar to the libs folders of library project 1?
Well I can think of a solution to use an Ant task to copy the file to the libs folder, but then I have to modify the build.xml which I do not prefer.
** EDIT
The problem is that the R class is missing, when I look in classes.jar this java file does not contain the R class. So my solution would proberly not work.
This behaviour was caused by a change in R17 of the build tools: http://tools.android.com/recent/dealingwithdependenciesinandroidprojects
In a nutshell: R files for libraries are no longer packaged in the classes.jar for that library. However, since the pareent.R for the parent-library (project1 in your example) also contains the resource-references for the 'child' library (project2 in your example), you don't have to refer to the child-R anyway.
Replace all project2.R-import statements in project1 with project1.R import statements and you should be fine.
For ant to compile add dependency in ant.properties.
eg:
android.library.reference.1=../path/to/library
This sounds like a very brittle setup - you may have good reason for this, but could you instead decouple the libraries dependence on each other?
For example; implement a bridge pattern to translate the calls between both libraries, and make the calling Android project attach them. This way, you have no code in either library that depends on the other, and the only project that needs to handle dependency setup is your main project.
One of the main reasons for using a library is to make the code re-usable, this approach ensures someone (you, a colleague, your successor...) could plug in just one library and create their own implementation of the other one.
Here is another good article on applying the bridge pattern in Java: http://java.dzone.com/articles/design-patterns-bridge
Well the problem was that the R class was missing.
So i removed the R class dependency between the two library projects.
I don't know if this is fixable but i think it is bad practice any way.
Without this dependency Ant builds fine.
Old question, but like me, others might be banging their head on this...
The official answer is "it cannot be done", specifically:
At build time, the libraries are merged with the application one at a time, starting from the lowest priority to the highest. Note that a library cannot itself reference another library and that, at build time, libraries are not merged with each other before being merged with the application.
(extracted from the official documentation: "Referencing a Library Project").
Which means that anything goes, as there is no "clean" way to do it with the tools (and dirty methods are in order).
Hope it helps