How do I share dependencies between Android modules - android

I have an Android application module (app) and an Android library module (library). Both app and library contain these same dependencies:
dependencies {
compile 'com.squareup.okhttp:okhttp:2.4.0'
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'io.reactivex:rxjava:1.0.13'
compile 'io.reactivex:rxandroid:0.25.0'
}
However when I try to add that block to the project build.gradle, it complains about not knowing the "compile" DSL.
EDIT: I'm asking about putting this dependencies block in the PROJECT build.gradle, to avoid repeating in each module's build.gradle.

As of Gradle Plugin version 3.0.0 there is a nicer way to do this. We can control whether each dependency is available for only the current module, or for the current module AND any modules which depend on it. This will allow us to easily share dependencies across modules within a project.
Here's how we used to declare dependencies:
compile 'example.dependency:1.0.0'
Here are the new configurations which should replace compile:
implementation 'example.dependency:1.0.0' --> this dependency is only used within this module
api 'example.dependency:1.0.0' --> this dependency will also be available in any builds that depend on this module
Here's how to do that with the architecture you mentioned in the question. Assuming that we have a module named 'library' that is consumed by the 'app' module, we can use the api configuration to declare that the dependency should be shared with any module that depends on it.
library module build.gradle
dependencies {
// dependencies marked 'implementation' will only be available to the current module
implementation 'com.squareup.okhttp:okhttp:2.4.0'
// any dependencies marked 'api' will also be available to app module
api 'com.squareup.retrofit:retrofit:1.9.0'
api 'io.reactivex:rxjava:1.0.13'
api 'io.reactivex:rxandroid:0.25.0'
}
app module build.gradle:
dependencies {
// declare dependency on library module
implementation project(':library')
// only need to declare dependencies unique to app
implementation 'example.dependency:1.0.0'
}
Please see this guide for further information and diagrams.

The dependencies block(closure) needs DependencyHandler as delegate
You need to pass DependencyHandler of each project to shared dependencies in project gradle.build.
project build.gradle
ext.sharedGroup = {dependencyHandler->
delegate = dependencyHandler
compile 'com.squareup.okhttp:okhttp:2.4.0'
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'io.reactivex:rxjava:1.0.13'
compile 'io.reactivex:rxandroid:0.25.0'
}
app build.gradle
dependencies {
sharedGroup dependencies
}
ref. https://github.com/b1uec0in/DependencyVersionResolver
(see 2. Using default dependency group.
This sample explains many other tips for sharing library version, sdk versions ... for large project that have many modules.)

You can define shared gradle dependencies in the library module, and if the app module has the library as a dependency, you won't need to specify everything twice. Taking this further, you could create a 'common' module that requires the shared gradle dependencies, and have both the app & library module require the common module.

You could do something like this where the project build.gradle will specify the dependencies needed as variable names then in the app build.gradle files you just need to include the variable names. This is very useful when you have many modules and don't want to edit everyone when a version number changes!
project build.gradle
buildscript {
ext {
googlePlayServicesVersion = '7.5.0'
supportLibVersion = '22.2.0'
}
... (the rest of your repositories/dependency info here) ...
}
ext {
minSdkVersion=16
targetSdkVersion=21
buildToolsVersion='22.0.1'
compileSdkVersion=21
//Android Dependencies
supportV4 = 'com.android.support:support-v4:' + supportLibVersion
supportAnnotations = 'com.android.support:support-annotations:' + supportLibVersion
recyclerView = 'com.android.support:recyclerview-v7:' + supportLibVersion
cardView = 'com.android.support:cardview-v7:' + supportLibVersion
palette = 'com.android.support:palette-v7:' + supportLibVersion
appCompat = 'com.android.support:appcompat-v7:' + supportLibVersion
multidex = 'com.android.support:multidex:1.0.1'
appCompat = 'com.android.support:appcompat-v7:' + supportLibVersion
supportDesign = 'com.android.support:design:' + supportLibVersion
playServicesAnalytics = 'com.google.android.gms:play-services-analytics:' + googlePlayServicesVersion
}
app build.gradle file
dependencies {
compile rootProject.ext.supportV4
compile rootProject.ext.appCompat
compile rootProject.ext.supportAnnotations
compile rootProject.ext.recyclerView
compile rootProject.ext.cardView
compile rootProject.ext.palette
compile rootProject.ext.appCompat
compile rootProject.ext.multidex
compile rootProject.ext.supportDesign
compile rootProject.ext.playServicesAnalytics
}
Hope that this helps!

Share libraries using ext block in the root project module
This is an easy way to use the library across all modules in the
android project
Please follow these steps:
Add ext block (it is used to define extra properties for the project) in root project gradle file
Add common libraries in with variable name in ext block
e.g name = [
libraries without implementation keyword
]
Used this ext block in module level using implementation and variable name
e.g implementation variable_name
See below code for complete implementation
build.gradle :project
buildscript {
... (the rest of your repositories here) ...
}
ext { **// ext block start here**
appModuleLibraries = [
commonLibraries,
/*Projects*/
project(':hco-cutout'),
project(':utils')
]
commonLibraries = [
/*Android Libs*/
'androidx.core:core-ktx:1.7.0',
'androidx.appcompat:appcompat:1.4.1',
'com.google.android.material:material:1.5.0',
'androidx.constraintlayout:constraintlayout:2.1.3',
/*Gesture viw for image zooming */
'com.alexvasilkov:gesture-views:2.5.2',
]
cutoutModulleLibraries = [
commonLibraries,
project(':utils'),
// Selfie segmentation
'com.google.mlkit:segmentation-selfie:16.0.0-beta4',
/*checker board drawable*/
'com.github.duanhong169:checkerboarddrawable:1.0.2',
]
} **// ext block end here**
build.gradle :app
dependencies {
/*App Module Libraries in root project gradle*/
implementation appModuleLibraries
}
build.gradle :cutout
dependencies {
/*cutout Module Libraries in root project gradle*/
implementation cutoutModulleLibraries
implementation project(':utils')
}
Hope that this helps!

Based on #SMKS answer, I would prefer this solution for transitive option capability and simplicity
project build.gradle
buildscript {
... (the rest of your repositories/dependency info here) ...
}
ext {
googlePlayServicesVersion = '7.5.0'
supportLibVersion = '22.2.0'
}
app build.gradle file
dependencies {
compile 'com.android.support:support-v4:' + supportLibVersion
compile ' com.android.support:support-annotations:' + supportLibVersion
compile = 'com.android.support:recyclerview-v7:' + supportLibVersion {
transitive = true // do not know if this make sens/interest just for example
}
...
}

Related

Unable to find method 'com.android.tools.r8.Version.getVersionString()Ljava/lang/String;'

I have updated my android studio to 3.4.
I am getting error while making release build.
Unable to find method
'com.android.tools.r8.Version.getVersionString()Ljava/lang/String;'.
Possible causes for this unexpected error include:
Gradle's dependency cache may be corrupt (this sometimes occurs after
a network connection timeout.)
Re-download dependencies and sync project (requires network)
The state of a Gradle build process (daemon) may be corrupt. Stopping
all Gradle daemons may solve this problem.
Stop Gradle build processes (requires restart)
Your project may be using a third-party plugin which is not compatible
with the other plugins in the project or the version of Gradle
requested by the project.
In the case of corrupt Gradle processes, you can also try closing the
IDE and then killing all Java processes.
I have updated my dependencies in gradle
Here is my gradle file
dependencies {
//Retrofit networking libraries
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
//Use for converting JsonObject to Plain Text in retrofit
implementation 'com.squareup.retrofit2:converter-scalars:2.1.0'
//http logging interceptor
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'
// For circular progressbar design
implementation 'me.relex:circleindicator:1.2.2#aar'
//Crashlytics library dependency
implementation('com.crashlytics.sdk.android:crashlytics:2.6.5#aar') {
transitive = true;
}
//ViewModel concept used in
implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'android.arch.lifecycle:livedata-core:1.1.1'
//RangeSeekBar Design
implementation 'com.yahoo.mobile.client.android.util.rangeseekbar:rangeseekbar-library:0.1.0'
//Clevertap events
implementation 'com.clevertap.android:clevertap-android-sdk:3.2.0'
//For volley networking library implementation
implementation 'com.android.volley:volley:1.1.0'
//For token passing classes
implementation 'com.auth0.android:jwtdecode:1.1.1'
//Rooted device finding library
implementation 'com.scottyab:rootbeer-lib:0.0.7'
//Facebook integration
implementation 'com.facebook.android:facebook-android-sdk:4.35.0'
//New Relic interation library
implementation 'com.newrelic.agent.android:android-agent:5.9.0'
//Calender library
implementation project(':library')
//Channel level encryption library
implementation files('libs/bcprov-jdk15on-160.jar')
//Injection tool
annotationProcessor 'com.jakewharton:butterknife:6.1.0'
implementation 'com.jakewharton:butterknife:6.1.0'
/*annotationProcessor 'com.jakewharton:butterknife:10.1.0'
implementation 'com.jakewharton:butterknife:10.1.0'*/
//Image Loading library
implementation 'com.github.bumptech.glide:glide:3.7.0'
//Secure SQLite Database
implementation 'net.zetetic:android-database-sqlcipher:3.5.9#aar'
//Branch .io library
implementation('io.branch.sdk.android:library:2.+') {
exclude module: 'answers.shim'
}
//noinspection GradleCompatible
implementation 'com.android.support:appcompat-v7:26.0.2'
implementation 'com.android.support:design:26.0.2'
implementation 'com.google.android.gms:play-services:11.0.1'
implementation 'com.google.android.gms:play-services-maps:11.0.1'
implementation 'com.google.firebase:firebase-core:11.0.1'
implementation 'com.google.firebase:firebase-messaging:11.0.1'
implementation 'com.android.support:support-v4:26.0.2'
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation project(':mpointintegration')
}
I am not using kotlin.
I checked various resources like below but none worked
java.lang.NoSuchMethodError - Ljava/lang/String;)Ljava/lang/String;
Android Studio 3.0 - Unable to find method 'com.android.build.gradle.internal.variant.BaseVariantData.getOutputs()Ljava/util/List'
also tried with
Re-download dependencies and sync project
&
Stop Gradle build processes (requires restart)
but none worked.
Project Level gradle File
// Top-level build file where you can add configuration options common
to all sub-projects/modules.
buildscript {
repositories {
jcenter()
mavenCentral()
google()
maven { url "http://storage.googleapis.com/r8-releases/raw"}
}
dependencies {
classpath ('com.android.tools:r8:1.3.52' ) { transitive false }
classpath 'com.android.tools.build:gradle:3.4.0'
classpath 'com.google.gms:google-services:4.2.0'
classpath "com.newrelic.agent.android:agent-gradle-plugin:5.9.0"
// NOTE: Do not place your application dependencies here; they
belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
maven {
url 'https://maven.google.com'
}
// maven { url 'https://jitpack.io' }
google()
}
}
ext {
minSdkVersion = 15
targetSdkVersion = 26
compileSdkVersion = 26
buildToolsVersion = '26.0.2'
sourceCompatibilityVersion = JavaVersion.VERSION_1_8
targetCompatibilityVersion = JavaVersion.VERSION_1_8
}
task clean(type: Delete) {
delete rootProject.buildDir
}
ext.deps = [
// Test dependencies
junit : 'junit:junit:4.10',
festandroid: 'com.squareup:fest-android:1.0.7',
robolectric: 'org.robolectric:robolectric:2.2',
intellijannotations: 'com.intellij:annotations:12.0'
]
The issue is that you have a fixed version dependency on R8 1.3.52:
classpath ('com.android.tools:r8:1.3.52' ) { transitive false }
And the com.android.tools.r8.Version method
public String getVersionString()
is only present in the R8 1.4 versions and above.
I assume that you are using a fixed version of R8 due to a bug fix in that version. However that should also be fixed in the latest version, so I suggest that you remove the fixed R8 version dependency and use what is shipped with Android Studio.
I solved it. From android studio 3.4 R8 versioning is added in android studio.
So i did some changes in my build.gradle file and gradle.properties file
In my app level build.gradle file in release section I added one line
useProguard false
& in gradle.properties file
android.enableR8=true
so it will use R8 Versioning to create my APK.
Incase if you dont want to use R8 versioning and want to continue with proguard then make
android.enableR8=false //in gradle.properties file
Hope this will help someone

Transloadit Dependency has different version for the compile (x) and runtime (y)

I want to add the transloadit android sdk. The gradle build fails with the following error:
Android dependency 'io.tus.android.client:tus-android-client' has
different version for the compile (0.1.5) and runtime (0.1.7)
classpath. You should manually set the same version via
DependencyResolution
I already use the dependencyResolution for the support library but I'm not sure what to do with transloadit. This is what I have so far.
configurations.all {
resolutionStrategy.force "com.android.support:support-v4:28.0.0"
resolutionStrategy.force "com.android.support:appcompat-v7:28.0.0"
}
I found a different version of the same library in one of the submodules that caused the problem.
In my case a was able to remove the other dependency. But if you have library that uses i.e. an older version of a library you have to use you can do the following:
As described here -> https://developer.android.com/studio/build/gradle-tips#configure-project-wide-properties
you can override the version number of libraries used in submodules and libraries by adding ext in your root folder and specify which version should be used. In my case I override the versions for android v4 and v7 support libraries and the play-service-location library.
Here is what I had to add to my root gradle file
ext {
compileSdkVersion = 28
supportLibVersion = "28.0.0"
googleMapsLibVersion = "16.0.0"
}
allprojects {
repositories {
google()
jcenter()
}
configurations.all {
resolutionStrategy.force "com.android.support:support-v4:${rootProject.ext.supportLibVersion}"
resolutionStrategy.force "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
resolutionStrategy.force "com.google.android.gms:play-services-location:${rootProject.ext.googleMapsLibVersion}"
}
}
and in my module "app" I can use these versions as well
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation "com.android.support:support-v13:${rootProject.ext.supportLibVersion}"
implementation "com.android.support:recyclerview-v7:${rootProject.ext.supportLibVersion}"
implementation "com.google.android.gms:play-services-location:${rootProject.ext.googleMapsLibVersion}"
implementation "com.google.android.gms:play-services-maps:${rootProject.ext.googleMapsLibVersion}"

How to include the third library in .arr with JCenter?

In my android library project I include many third-party libraries like
compile 'com.jakewharton:butterknife:8.0.1'
apt 'com.jakewharton:butterknife-compiler:8.0.1'
// Java8的时间库
compile 'com.jakewharton.threetenabp:threetenabp:1.0.3'
// RxJava
compile 'io.reactivex:rxjava:1.1.5'
compile 'io.reactivex:rxandroid:1.2.0'
when I used ./gradlew install build arr not include this third library. So my other project can't reference this library.
but when I include Rosie project (https://github.com/Karumi/Rosie). I can auto include dagger, butterknife....
How can I do it?
I want my library to include these third-party libraries in my arr.What can i do?
You must include these lines in your build.gradle to use Butterknife :
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
apply plugin: 'com.neenbedankt.android-apt'

Can android gradle resolve module libraries' dependencies automatically?

Setup
I have an android project setup in such a way that: Main depends on Module A and Module A depends on Module B.
Both A and B are compiled to aar files and uploaded to local maven repository. And in Main project, the importing of Module A is explicit.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile(group: 'com.test', name: 'ModuleA', version: '0.0.1', changing: true)
}
Error
When running the Main project, it failed with NoClassDefFoundError at places where Module A uses Module B.
This error is gone once I explicitly import Module B into Main project.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile(group: 'com.test', name: 'ModuleA', version: '0.0.1', changing: true)
compile(group: 'com.test', name: 'ModuleB', version: '0.0.1', changing: true)
}
Question
Can't gradle resolve the dependencies automatically? Or do I have to include all Module A's dependencies in the build.gradle of Main project?
I think it is related to the pom file generation, in pom file you can define dependency section. How do we let gradle know to include the dependencies in generating the pom file?
Edit #1
The build.gradle for ModuleA is like the following:
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile(group: 'com.test', name: 'ModuleB', version:'0.0.1', ext: 'aar', changing: true)
}
publishing {
publications {
aar(MavenPublication) {
groupId packageId
version = versionId
artifactId libraryId
artifact("$buildDir/outputs/aar/${project.getName()}-debug.aar")
}
}
}
artifactory {
contextUrl = "${artifactory_contextUrl}"
publish {
repository {
repoKey = 'libs-release-local'
maven = true
username = "admin"
password = "password"
}
defaults {
publications('aar')
publishArtifacts = true
properties = ['qa.level': 'basic', 'dev.team': 'core']
publishPom = true
}
}
resolve {
repository {
repoKey = 'libs-release'
maven = true
}
}
}
What do you mean by "automatically"? If the dependency does not exist in a defined path with well-defined names in your gradle.build, it will not find it. What may be misleading is that references to libraries in repositories can include dependencies to other libraries. When gradle requests the library location, the server responds with a file that specifies the location and dependencies, if applicable.
An aar file does not include your gradle.build or another dependency file that gradle can use, so any dependencies defined in your Module A gradle.build are not available to your main gradle.build. So you can't expect gradle to go to the source location of your Module B because it isn't there.
I think libraries in repositories do not make this clear because if a library with dependencies is in a repo then those dependencies seem to "magically" be included when you do a build. This is because the library reference can include references to the other dependencies and gradle is given that information when it requests the library. The repo library entry/definition includes dependencies.
If this is the type of behavior you are looking for, you should put your aar in a repo (public or self-hosted) and then create an appropriate library definition in the repo (like a pom.xml file), specify the dependency and add the dependency library to the repo also.
EDIT:
Also gradle does not support parsing pom files natively. So you cannot directly reference a pom file to identify dependencies. However, it will work with repositories that identify dependencies (and those repositories can use pom files, but gradle does not parse them). See the docs here: https://docs.gradle.org/current/userguide/dependency_management.html
Also, see the related question about gradle's lack of support for parsing pom files: Reading info from existing pom.xml file using Gradle?
Finally find a solution for gradle to generate pom with dependencies, add the following to publishing task:
pom.withXml {
def dependencies = asNode().appendNode('dependencies')
configurations.getByName("_releaseCompile").getResolvedConfiguration().getFirstLevelModuleDependencies().each {
def dependency = dependencies.appendNode('dependency')
dependency.appendNode('groupId', it.moduleGroup)
dependency.appendNode('artifactId', it.moduleName)
dependency.appendNode('version', it.moduleVersion)
}
}

How to use the "provided" keyword in gradle's build.gradle dependencies

I'm new to gradle. Please help me understand how to use the keyword "provided" that is in build.gradle dependencies block.
And what is the difference between this "provided" with "providedCompile" and "providedRuntime"?
build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
...
dependencies {
def presentationDependencies = rootProject.ext.presentationDependencies
def presentationTestDependencies = rootProject.ext.presentationTestDependencies
compile project(':domain')
compile project(':data')
apt presentationDependencies.daggerCompiler
compile presentationDependencies.dagger
compile presentationDependencies.butterKnife
compile presentationDependencies.recyclerView
compile presentationDependencies.rxJava
compile presentationDependencies.rxAndroid
provided presentationDependencies.javaxAnnotation //what is this???
...
}
EDIT
The project in question has no mention of
configuration {
provided
}
and it still compiles!
The project is Android-cleanArchitecture
TIA
Gradle has no built in support for the provided dependency scope.
However this blog (credit goes to Danny, the blog's writer) describes how it can be emulated.
In short you need to provide a new configuration named "provided":
configurations {
provided
}
Then add this configuration to the relevant source sets configurations:
sourceSets {
main.compileClasspath += configurations.provided
test.compileClasspath += configurations.provided
test.runtimeClasspath += configurations.provided
}
And finally you're good to go:
dependencies {
provided <your dependency>
}
Note that according to the blog post if you're using Eclipse there's a "major flaw" but the post also provides a workaround for that.

Categories

Resources