Gradle multi-module dependecy issue - android

Information
So I have this project structure that looks like this:
Project root:
| Resources-module (uses the packagename: com.derk.application.resources)
-+ src
---+ main
-----+ res
| Core-module (uses the packagename: com.derk.application)
-+ src
---+ main
-----+ src
| Brand-module (uses whatever packagename of the customer domain)
Resources-module contains the res files.
Core contains a git-module that contains code for a code-base we keep updated.
Brand contains build.gradle where I setup the packagename of our customer and bind the main/res directory to the resource-module main/res, and then the main/src to the core-module main/src folder.
Like this:
android.sourceSets.main {
manifest.srcFile "src/main/AndroidManifest.xml"
res.srcDirs = ["$rootDir/resources-module/src/main/res"]
java.srcDirs = ["$rootDir/core-module/src/main/java", "src/main/java"]
}
}
I do not wish to alter the Core-module sources under any circumstances without it being pushed up to the master repository, meaing I only make global changes/fixes for all projects that uses core-module. This is why i tried this structure out.
The sourcefiles in the core-module will loads the imports
import com.derk.application.resources.R;
import com.derk.application.resources.BuildConfig;
to handle the resource generated content from gradle/idea
Since Brand-module is due to having packagename changes, I have to use some sort of middlemodule that holds the R and BuildConfig for easy deployment, so that the core-sources indeed never have local modifications.
When i try to refresh gradle for the brand-module, i do not get any issues, and android studio seems to find the R.java and BuildConfig.java just fine in the com.derk.application.resources when I check out the linkage in Android Studio
HOWEVER
When I try to run Brand-module, i get:
"Execution failed for task ':core-module:compileReleaseJava'."
and it now instead shows me:
Error:(20, 39) error: package com.derk.application.resources does not exist
even thought I have added
dependencies {
compile project(':resources-module')
}
to the build.gradle of core-module.
So the question is:
How do I setup gradle to handle this kind of cross-module dependency?
Keep in mind, I do not wish to alter the packagename for the core-module imports for each new project I setup, because we get local changes made to a gitmodule that is used for several projects.
/.ps
Currently i can without problem run module resources-module and have the app running, with the static packagename i've chosen for it. But that is also the problem, I want to keep it static, and hence that is why i introduced the third module.

You do that in the wrong way. What you are trying to achive is implementing a normal library module (which you use for every customer). Then you can create a new Module from the type application which uses the shared module. In that case you don't need to mess around with the path of the shared module.
For the case that your shared module is in another directory than the project root you can use this settings.gradle:
include ':CustomerX', ':SharedModule'
project(':SharedModule').projectDir = new File('../../some/where/else')
If not you can omit the last line.
When you keep a old directory structure you should try using this build.gradle:
apply plugin: 'com.android.library'
android {
compileSdkVersion 9
buildToolsVersion '21.0.1'
defaultConfig {
minSdkVersion 9
targetSdkVersion 21
}
sourceSets {
main {
assets.srcDirs = ['assets']
res.srcDirs = ['res']
aidl.srcDirs = ['src']
resources.srcDirs = ['src']
renderscript.srcDirs = ['src']
java.srcDirs = ['src']
manifest.srcFile 'AndroidManifest.xml'
}
}
}
dependencies {
// just as example
compile 'com.android.support:support-v4:21.0.2'
}
You customers build.gradle should look e.g. like this:
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion '21.0.1'
defaultConfig {
minSdkVersion 9
targetSdkVersion 21
signingConfigs {
release {
storeFile file("your.keystore")
storePassword 'pwd1'
keyAlias "alias"
keyPassword 'pwd2'
}
}
buildTypes {
debug {
debuggable true
minifyEnabled false
shrinkResources false
}
release {
debuggable false
jniDebuggable false
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
dependencies {
// dependencies of the main project
compile 'com.android.support:support-v4:21.0.0'
compile 'com.android.support:appcompat-v7:21.0.0'
compile project(':SharedModule')
}

Related

Android project compiles and runs without module-level build.gradle. Is it right?

I have got a 3 years old project (Android service) where there is only a top level (project-level) build.gradle file.
The file looks like this:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
}
}
apply plugin: 'com.android.application'
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
}
android {
compileSdkVersion 21
buildToolsVersion "22.0.1"
productFlavors {
arm {
ndk {
abiFilters = ["armeabi-v7a", "arm64-v8a"]
}
}
}
defaultConfig {
applicationId "com.mycompany.myapp"
minSdkVersion 17
targetSdkVersion 19
versionCode 1
versionName "9.99.99.99"
}
signingConfigs {
release {
storeFile file("myapp.jks")
storePassword "mypwd"
keyAlias "myalias"
keyPassword "mykeypwd"
}
}
buildTypes {
release {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug{
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
// Move the tests to tests/java, tests/res, etc...
instrumentTest.setRoot('tests')
// Move the build types to build-types/<type>
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
// This moves them out of them default location under src/<type>/... which would
// conflict with src/ being used by the main source set.
// Adding new build types or product flavors should be accompanied
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
}
All documents and tutorials I have read, including Google and Gradle official documentation, state that there should be 2 Gradle files, project-level and module-level.
My project has only one, project-level, build.gradle file, that looks like a combination of two. The project compiles and runs without any problem. So, is the module-level build.gradle a must if the project has only one module?
one does not necessarily require modules (that was common at times of Eclipse IDE with Android ADT and ant or mvn), while you could split the file at apply plugin: 'com.android.application'and move that into a sub-directory and reference it as a module in settings.gradle (which became merely the standard with Android Studio).
it basically depends, if one may require further modules in a project - and while having a project with one sub-project by default, it's less effort to add and/or remove further modules, without having to mess around first. also, this can reduce build times, when not always having to rebuild the whole code-base, but only the module one has changed.

enabling Robotium in Android

I recently decided to switch from Eclipse to Android Studio. While i was able to import my android project, i keep having problems setting up and transfering my unit tests. For testing purposes i made a directory in src folder (java folder and test package). For enabling robotium i followed another stack topic by adding androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.2.1'. Eventually i added my test java file from Eclipse. And when i try to run tests, i keep getting "Cannot resolve symbol Solo".
I have little understanding about how AS and gradle works, so probably i am missing something else.
The contents of my build.gradle file:
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "com.colormindapps.work_rest__scheduler"
minSdkVersion 8
targetSdkVersion 21
testApplicationId "com.colormindapps.work_rest__scheduler.test"
testInstrumentationRunner "android.test.InstrumentationTestRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/tests/java']
}
}
}
dependencies {
androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.2.1'
compile 'com.android.support:support-v4:19.0.+'
compile 'com.android.support:appcompat-v7:19.0.+'
}
I think the easiest way to make it work is to install Robotium Recorder for Android Studio. After you record a test you can see how Robotium Recorder sets up the gradle files etc.
http://robotium.com/pages/installation-android-studio
You must use separate source set for you android-specific tests, i.e.:
sourceSets {
main {
java.srcDirs = ['src/main/java']
}
androidTest {
java.srcDirs = ['src/tests/java']
}
}
Use androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.5.4' which resolve all test cases issues

Custom build Android app from command line

I'm trying to make a batch file with some commands, so once it runs, it will change some strings in the files, build the project and generate the APK signed.
The strings I need to change are:
- The package name (com.company.project)
- Some images (like icons, splash screen, ...)
- some irrelevant string that are specific from the app.
For the last 2 things I know how to do it, but for the package name I feel there is something wrong about just find and replace all the occurrences of that string in the root folder of the app (including subdirectories).
Is there any way or command that ant has for doing this?
Also I ran into an issue while running the command ant release.
I went to my root folder, ran the command and it gets errors.
So I had to go to eclipse, clean the project and let it autobuild (with no generation of APK since it does that when you try to run it on a device) so at that point my bin folder just contains the folders: classes, dexedLibs, res and the Manifest.xml file.
Then I can go to the CL and run ant release.
So is there any way to do all this from CL? Something like clean and build so I can run ant release command after with no issues?
NOTE: for find and replace I use an .exe called FNR that does the job
EDIT:
I'm now using gradle and can build changing the package name but there is still a few things I want to do in the build.gradle file and can't make it work.
This is build.gradle:
task("hello"){
println "Hello world!!"
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.8.+'
}
}
apply plugin: 'android'
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
}
android {
compileSdkVersion 19
buildToolsVersion "19.0.3"
productFlavors {
flavor1 {
packageName "com.testCompany.testProject"
}
}
signingConfigs {
release {
storeFile file("keystore/android.keystore")
storePassword 'blah blah'
keyAlias "blah blah"
keyPassword 'blah blah blah'
}
}
buildTypes {
flavor1 {
zipAlign true
sourceSets {
main {
signingConfig signingConfigs.release
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
}
}
}
}
I am pretty sure I'm doing things wrong.
So I want to:
- Change some strings in the res/strings.xml file.
- Change the icon/png files in the res/drawable.... folder for custom ones.
I have completely no idea of how to do it. I tried:
buildTypes{
flavor1{
copy{
from('src/res/'){
include '**/*.xml'
filter{String line -> line.replaceAll(string_to_be_replaced, replaced_string)}
}
into '$buildDir/res'
}
}
}
but nothing
The strings I need to change are: - The package name (com.company.project)
If you are changing these things based upon whether this is a debug build or a release build, you can specify a suffix on the package name for a build type:
android {
buildTypes {
debug {
packageNameSuffix ".debug"
}
}
}
Or, if you are changing these things for anything else, you can create product flavors and replace the package name per flavor:
android {
productFlavors {
flavor1 {
packageName "com.example.flavor1"
}
flavor2 {
packageName "com.example.flavor2"
}
}
}
Some images (like icons, splash screen, ...) - some irrelevant string that are specific from the app.
You can create source sets for build types (e.g., src/debug/) or product flavors (e.g., src/flavor1/) and have replacement versions of resources in them. That will handle your images, as well as your "irrelevant string" if you define it as a string resource.
Source sets can also have Java code, though that gets incrementally more complex, so I would recommend that you use the string resources and replacement resources instead.

Include .java files as java source files in Android Studio to remove red circle with "J" on them

Today after update android studio my source folder in project marks as below("J" inside a red circle mark). How can I fix it? I tried clear caches, re-import project, use gradlew clean build, but it doesn't help.
build.gradle
apply plugin: 'android'
apply plugin: 'android-apt'
android {
compileSdkVersion 19
buildToolsVersion "19.0.3"
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
}
defaultConfig {
minSdkVersion 14
targetSdkVersion 19
versionCode 1
versionName "1.0"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
lintOptions {
abortOnError false
}
}
def AAVersion = '3.0.1'
dependencies {
......
}
apt {
arguments {
....
}
}
I found some magical solution while playing with this
There are two possible solution you can try to make it correct (tricky one)
1.Replace this in your build.gradle file
java.srcDirs = ['src'] to java.srcDirs = ['src/com']
2.Create a subdirectory inside src name it whatever you want, I prefer name it java like
src > java
move all your java package in to it and change the
java.srcDirs = ['src'] to java.srcDirs = ['src/java']
These are the tricky solutions. It can be considered as a bug in Android Studio that it is not considering the java source set if it is the root of src directory but compiles fine.
After doing all the necessary changes sync your project with gradle and your yellow directory will be magically turned into blue.
Note : Even you have them in root there will be no effect on compilation as per my experience. Only Studio will not mark them as java sourcesets in IDE.
I solved it just closing the project from android studio and remove the project from recent project. Re-import the project, it worked. If any one facing for android project he/she can try this. Thanks
Open Project Structure in Android Studio(Cmd+;)
Under modules Header over the left of the window, look onto right side of it , You will get to see three tabs one of which is Sources ,Select it.
There, you will find the structure of your project which you have imported or might have created by self.
Go for the src folder of it and wait for the sources link above that dialog with many others to get avail to apply onto it,grab it.
Apply and OK
Problem Solved.
This is bug https://code.google.com/p/android/issues/detail?id=66758 and should be fixed in Android Studio 0.5.1, which is out now.
Open build.gradle file (one in module, not in project)
As you open it you will see "This folder does not belong to a Gradle project. Make sure it is registered in settings.gradle." message, and "Add now..." link in upper-right corner
Click "Add now" and Gradle will do its job.
If you are facing this issue after maybe switching branch or after taking pull. Then you can fix it by going in to File>Invalidate Caches/restart.

How to setup flavors for android gradle project? Mysterious duplicate class error

I have created simple test project: the goal is to show the message 'hello' by pressing a button on the screen. The first flavor build should write the message to the system log. The second flavor build should show a toast with message. How can this be achieved using gradle please?
My build.gradle:
apply plugin: 'android'
android {
compileSdkVersion 19
buildToolsVersion "19.0.1"
defaultConfig {
minSdkVersion 14
targetSdkVersion 19
versionCode 1
versionName "1.0"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
productFlavors {
toast {
}
log {
}
}
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/log/java']
}
toast {
java.srcDirs = ['src/main/java', 'src/toast/java']
}
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}
File structure:
Flavor log contains single class Messenger with method showMessage(Context context, CharSequence text) and prints text using Log.i(tag, msg)
Flavor toast contains single class Messenger with method showMessage(Context context, CharSequence text) and shows toast with some text.
Main sources don't contain this class.
Why does the error duplicate class:com.test.flavortest.Messenger appear? Each flavor has a set of different non-crossing source paths?
Full sample project, zipped
In your sourcesets definition, you seem to be adding the log sources to main:
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/log/java']
}
toast {
java.srcDirs = ['src/main/java', 'src/toast/java']
}
}
main is the default sourceset included in all flavors. This would cause a duplicate class (Messenger) being loaded when building the toast flavor.
Try specifying the log and toast sourcesets only:
sourceSets {
log {
java.srcDirs = ['src/main/java', 'src/log/java']
}
toast {
java.srcDirs = ['src/main/java', 'src/toast/java']
}
}
Your file structure seems to match the default, so an even better solution would be to remove the sourcesets block entirely. src/main/java is included by default, and then src/flavor/java is added afterwards automatically.
Use assembleToast / assembleLog to Build an specific Flavour.
Same for installToast e.g
The global assemble will use every File in the directory.
All source code in the java/ directories are compiled together to generate a single output.
Note: For a given build variant, Gradle throws a build error if it encounters two or more source set directories that have defined the same Java class. For example, when building a debug APK, you cannot define both src/debug/Utility.java and src/main/Utility.java. This is because Gradle looks at both these directories during the build process and throws a 'duplicate class' error. If you want different versions of Utility.java for different build types, you can have each build type define its own version of the file and not include it in the main/ source set.

Categories

Resources