I am currently in the process of converting one of our projects to Gradle from maven. The folder structure is as follows:
gitRoot
settings.gradle
bui
I have finally managed to build the project (without gradle errors). Answer from Xavier was very helpful.
I spend almost 3 days trying to setup my project, I know I am very close to be finsihed but I have UNEXPECTED TOP-LEVEL EXCEPTION at very last step of gradle build process (dexDebug).
My project setup is very similar to Stoyan's however I have multiple android-library projects that are referencing android-support libraries. I suggest that if you have problems with compiling your top root project (error saying support android is already added) than you need to move the jar into separate android library project (decompose/separate into stand alone instance).
Example
--| ProjectARoot
--| ProjectA (where main/java etc are)
--| build.gradle
--| settings.gradle
--| libraries
--| ProjectBRoot
--| settings.gradle
--| ProjectB
--| libraries
--| android-supports (android lib project)
--| libs
--| android-support-v4.jar
--| android-support-v13.jar
--| build.gradle
--| libA
--| build.gradle (referencing android-supports)'
Example build scrip for libA referencing android supports projects
buildscript {
repositories {
maven { url 'http://repo1.maven.org/maven2' }
}
dependencies {
classpath 'com.android.tools.build:gradle:0.4'
}
}
apply plugin: 'android-library'
dependencies {
compile project(':android-support')
}
android {
compileSdkVersion 17
buildToolsVersion "17.0.0"
defaultConfig {
minSdkVersion 7
targetSdkVersion 17
}
}
// top root settings.gradle
include 'ProjectB', 'android-support', ':ProjectA' (notice Project B is first than android-support and lastly Project A)
project(':android-support').projectDir = new File('libraries/ProjectBRoot/libraries/android-support')
project(':ProjectB').projectDir = new File('libraries/ProjectBRoot/ProjectB')
Currently when I run gradle build I get this error
:ProjectA:dexDebug
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Landroid/support/v4/accessibilityservice/AccessibilityServiceInfoCompat;
at com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:123)
at com.android.dx.dex.file.DexFile.add(DexFile.java:163)
at com.android.dx.command.dexer.Main.processClass(Main.java:490)
at com.android.dx.command.dexer.Main.processFileBytes(Main.java:459)
at com.android.dx.command.dexer.Main.access$400(Main.java:67)
at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:398)
at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:245)
at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:131)
at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:109)
at com.android.dx.command.dexer.Main.processOne(Main.java:422)
at com.android.dx.command.dexer.Main.processAllFiles(Main.java:333)
at com.android.dx.command.dexer.Main.run(Main.java:209)
at com.android.dx.command.dexer.Main.main(Main.java:174)
at com.android.dx.command.Main.main(Main.java:91)
1 error; aborting
:ProjectA:dexDebug FAILED
I would just have the app with the libraries all at the same level. You can still build and package each library based on the build.gradle file. I might be missing something, but the structure isn't as important as what's in the build.gradle files. You could still have projectB depend on Facebook, even if they are at the same folder level.
Had the same problem, in my case, I just forgot to add the project in settings.gradle
. After that, it worked
settings.gradle must define all the modules. It won't load other settings.gradle found in the tree to load more module.
You'll have to either
define a module for the facebook SDK in the top level settings.gradle. Yes it's redundant with the other settings.gradle.
publish Project B somehow (as well as its dependencies so in this case the facebook SDK library), somewhere (a corporate artifact repository for instance) and access it from Project A.
While #1 is better, it makes the ProjectB -> Facebook dependency tricky as the path will be different depending on the settings.gradle used. One way to fix this is to split the module name/path from its actual location on disk. this is done inside the settings.gradle file.
In your top level settings.gradle file, do
include 'facebook-sdk'
project(':facebook-sdk').projectDir = new File('Libraries/ProjectBRoot/Libraries/FacebookSDK/facebook')
In the setting.gradle file inside your Project B, do the same with the different relative path:
include 'facebook-sdk'
project(':facebook-sdk').projectDir = new File('Libraries/FacebookSDK/facebook')
This makes both project setup define the same 'facebook-sdk' module located at the same absolute location on disk.
All projects depending on this module should just declare the dependency as
compile project(':facebook-sdk')
This isn't the answer that you are looking for, but...
I spent about 4 days trying to migrate my complex project structure (much like yours actually), into gradle. In the end, I ditched the entire sub-project concept (since in my case, it just didn't work), and I opted to use the local maven repository approach, as described in this article: http://www.flexlabs.org/2013/06/using-local-aar-android-library-packages-in-gradle-builds
So, in my Library projects that had sub-projects, I basically created complete library projects for each of those, and then I used the link above to publish those to the maven local repository. Then in the parent project, I removed any references to sub projects, and in the dependencies, I just referenced the published libraries. And then in my main project, I removed all references to sub-projects, and I referenced published maven local versions of my libraries.
In the end, it all works very well, but it did take some time to convert everything over. I had about 6 library projects with sub projects, that that sub projects, etc, and now everything works fine.
The thing that I dislike about systems like Gradle and Maven is that they really expect you to change "how" you structure your code/projects. So, if you are migrating to Gradle vs starting with Gradle, then the process can be quite frustrating. Once you figure it out though, the next time is much easier ;)