I have an application consist of multiple modules. Those modules has external dependencies like Google Maps, Glide etc. compiled with "api" on gradle. Thus i can use that dependencies in app module too. However, I started to publish those modules on some package repository like jitpack and dependencies compiled with "api" are no longer reachable in my app module. What should I do?
App --implements-> mymodule --api-> glide (It works)
App --implements-> my module published on package repository --api-> glide (I can't reach to glide in app)
Edit: The problem was, while I'm publishing my aar on maven, it does not include other dependencies into the pom file. I have solved with updating my gradle publish with this:
publications {
"${getPublicationName()}" (MavenPublication) {
groupId Config.groupId
artifactId Config.artifactId
version Config.versionName
artifact getArtifactFilePath()
pom.withXml {
def dependencies = asNode().appendNode('dependencies')
configurations.getByName("${getPublicationName()}CompileClasspath").getResolvedConfiguration().getFirstLevelModuleDependencies().each {
def dependency = dependencies.appendNode('dependency')
dependency.appendNode('groupId', it.moduleGroup)
dependency.appendNode('artifactId', it.moduleName)
dependency.appendNode('version', it.moduleVersion)
}
}
}
}
Related
When I build an app with a *.aar file instead of the module with Gradle 4.x and following the docu concerning implements and api, I expect using api the included aar file has all dependencies included, but it hasn't.
When you do
git clone https://github.com/hannesa2/aar_dependency
./gradlew clean assembleDebug
means
dependencies {
api project(':mylibrary')
it works properly.
But when I use insted of lib-module the previous generated *.aar file as dependency
dependencies {
api 'com.example.my.mylibrary:mylibrary-debug#aar'
(in demo app just do)
git checkout with_aar
./gradlew clean assembleDebug
I run into this
Task :app:transformClassesWithDesugarForDebug
Exception in thread "main" java.lang.TypeNotPresentException: Type io.reactivex.ObservableTransformer not present
at sun.invoke.util.BytecodeDescriptor.parseSig(BytecodeDescriptor.java:85)
at sun.invoke.util.BytecodeDescriptor.parseMethod(BytecodeDescriptor.java:63)
at sun.invoke.util.BytecodeDescriptor.parseMethod(BytecodeDescriptor.java:41)
at java.lang.invoke.MethodType.fromMethodDescriptorString(MethodType.java:1067)
at com.google.devtools.build.android.desugar.LambdaDesugaring$InvokedynamicRewriter.visitInvokeDynamicInsn(LambdaDesugaring.java:399)
at org.objectweb.asm.MethodVisitor.visitInvokeDynamicInsn(Unknown Source)
at org.objectweb.asm.MethodVisitor.visitInvokeDynamicInsn(Unknown Source)
Because I ordinary run into this with uploading the aar artifacts into our company Maven Nexus, I created this demo-repo to show exactly what's wrong. In demo app or using Maven I see the same issue.
Does someone knows what I did wrong ?
I was able to solve it. The main issue was Android O with Gradle 4.x using api
dependencies {
api 'com.squareup.okhttp3:logging-interceptor:3.4.1'
api "io.reactivex.rxjava2:rxandroid:$versions.libs.rxAndroid"
Most answers are concerning something like this
publishing {
publications {
mipartner(MavenPublication) {
groupId '...'
artifactId '..'
version 1.0
artifact "$buildDir/outputs/aar/myLib-release.aar"
//generate pom nodes for dependencies
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.compile.allDependencies.each { dependency ->
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dependency.group)
dependencyNode.appendNode('artifactId', dependency.name)
dependencyNode.appendNode('version', dependency.version)
}
}
}
}
repositories{
maven {
url "https://some.url.com"
}
}
}
but here in the resulting *.pom there are no dependencies included, after change this line to api the dependencies are included in deployed pom !
configurations.api.allDependencies.each { dependency ->
after this you can easily consume the aar file
dependencies {
api "com.mylib.net:mylib:1.0"
When I build an app with a *.aar file instead of the module with Gradle 4.x and following the docu concerning implements and api, I expect using api the included aar file has all dependencies included, but it hasn't.
When you do
git clone https://github.com/hannesa2/aar_dependency
./gradlew clean assembleDebug
means
dependencies {
api project(':mylibrary')
it works properly.
But when I use insted of lib-module the previous generated *.aar file as dependency
dependencies {
api 'com.example.my.mylibrary:mylibrary-debug#aar'
(in demo app just do)
git checkout with_aar
./gradlew clean assembleDebug
I run into this
Task :app:transformClassesWithDesugarForDebug
Exception in thread "main" java.lang.TypeNotPresentException: Type io.reactivex.ObservableTransformer not present
at sun.invoke.util.BytecodeDescriptor.parseSig(BytecodeDescriptor.java:85)
at sun.invoke.util.BytecodeDescriptor.parseMethod(BytecodeDescriptor.java:63)
at sun.invoke.util.BytecodeDescriptor.parseMethod(BytecodeDescriptor.java:41)
at java.lang.invoke.MethodType.fromMethodDescriptorString(MethodType.java:1067)
at com.google.devtools.build.android.desugar.LambdaDesugaring$InvokedynamicRewriter.visitInvokeDynamicInsn(LambdaDesugaring.java:399)
at org.objectweb.asm.MethodVisitor.visitInvokeDynamicInsn(Unknown Source)
at org.objectweb.asm.MethodVisitor.visitInvokeDynamicInsn(Unknown Source)
Because I ordinary run into this with uploading the aar artifacts into our company Maven Nexus, I created this demo-repo to show exactly what's wrong. In demo app or using Maven I see the same issue.
Does someone knows what I did wrong ?
I was able to solve it. The main issue was Android O with Gradle 4.x using api
dependencies {
api 'com.squareup.okhttp3:logging-interceptor:3.4.1'
api "io.reactivex.rxjava2:rxandroid:$versions.libs.rxAndroid"
Most answers are concerning something like this
publishing {
publications {
mipartner(MavenPublication) {
groupId '...'
artifactId '..'
version 1.0
artifact "$buildDir/outputs/aar/myLib-release.aar"
//generate pom nodes for dependencies
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.compile.allDependencies.each { dependency ->
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dependency.group)
dependencyNode.appendNode('artifactId', dependency.name)
dependencyNode.appendNode('version', dependency.version)
}
}
}
}
repositories{
maven {
url "https://some.url.com"
}
}
}
but here in the resulting *.pom there are no dependencies included, after change this line to api the dependencies are included in deployed pom !
configurations.api.allDependencies.each { dependency ->
after this you can easily consume the aar file
dependencies {
api "com.mylib.net:mylib:1.0"
I have been searching for an answer to my question, but I found none.
I built an android project with many modules. The modules should be published in a repository (at first in the local maven repository).
I've done a demo project with two simple projects pr1, pr2. Now I've added to pr2 the dependency for pr1.
compile ('de.test:project1:1.0.0')
After that, I can publish both artifacts.
Now, when I change the name from pr2 to aPr2, the dependency can not be resolved from in aPr2, because the jar file does not exist. The problem is that aPr2 is built before pr1.
How can I tell Gradle to build it in the correct order?
This is my Gradle file from one of the projects. Pr1 is similar, without dependency.
plugins {
id 'java'
id 'maven-publish'
}
dependencies {
// compile project(':project1')
compile ('de.test:project1:1.0.0')
testCompile 'junit:junit:4.12'
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
publishing {
publications {
publish(MavenPublication) {
groupId 'de.test'
artifactId 'project2'
version '1.0.0'
from components.java
}
}
}
You need to modify your project configuration.
When you use components.java, the maven-publish plugin will set the groupId, artifactId and version from Gradle project configuration.
The default artifactId has been set with the name of the project (default: folder name). It is read-only, but you can override it. Create a settings.gradle file in subproject folder and set the module name:
rootProject.name = 'project1'
Write these lines into build.gradle file in root project dir for setup groupId and version for all project.
allprojects {
group 'de.test'
version '1.0.0'
}
If you setup everything correctly, you can remove comment from compile project(':project1')
You can build the project and you can publish your pom file with de.test:project:1.0.0 dependency.
Since I cannot use a private maven in order to share my library, I was thinking in sharing the aar and importing into another project.
The problem comes when the aar and jar files does not contain any dependency. So once I manually import the aar in android studio (using Import .JAR/.AA Package) there is no dependency, and I have to manually add all dependencies again.
I already generated a pom file through a gradle task, although I cannot find any way to manually import it on the project.
On the build.gradle file automatically generated by the "Import .JAR/.AA Package" is:
configurations.maybeCreate("default")
artifacts.add("default", file('TestSample_1.0.0.aar'))
Is there a way to add the pom/iml file too? something like:
artifacts.add("default", file('pomDependencies.xml'))
1. Publishing
In your aar project, add maven-publish plugin and add necessary plugin configuration.
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
...
dependencies {
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.novoda:bintray-release:0.2.7'
}
...
publishing {
publications {
maven(MavenPublication) {
groupId 'com.example' //You can either define these here or get them from project conf elsewhere
artifactId 'example'
version '0.0.1-SNAPSHOT'
artifact "$buildDir/outputs/aar/app-release.aar" //aar artifact you want to publish
//generate pom nodes for dependencies
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.compile.allDependencies.each { dependency ->
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dependency.group)
dependencyNode.appendNode('artifactId', dependency.name)
dependencyNode.appendNode('version', dependency.version)
}
}
}
}
//publish to filesystem repo
repositories{
maven {
url "$buildDir/repo"
}
}
}
Few things to note:
We're using a custom maven publication, so you have to define what is being published with the artifact clause
We have to generate the pom ourselves, in the code above I'm using all compile config dependencies, you may want to make sure all the configs you care about are covered.
Running gradle publish will publish to a maven repo structure to the repo folder, which you can then consume from a different project.
2. Using published .aar
In a different android project, to use the aar published in #1:
In top level build.gradle:
allprojects {
repositories {
jcenter()
maven {
url "D:/full/path/to/repo"
}
}
}
add the path to earlier repo as a maven repository. Note that you may have to use the full path, because $buildDir has a different value for this project. In your app build.gradle:
dependencies {
...
other dependencies
...
implementation ('com.example:example:0.0.1-SNAPSHOT#aar'){transitive=true}
}
transitive=true is required for to fetch the transitive dependencies from the pom file.
Things have changed a little, here's how you do it with the latest versions of gradle
Create the package localy (aar and pom)
Modify your library build.gradle file to include
apply plugin: 'maven-publish'
android {
...
...
}
dependencies {
...
...
}
publishing {
publications {
maven(MavenPublication) {
groupId 'com.domain' //You can either define these here or get them from project conf elsewhere
artifactId 'name'
version '1.0.0'
artifact "$buildDir/outputs/aar/sdk-release.aar" //aar artifact you want to publish
//generate pom nodes for dependencies
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.implementation.allDependencies.each { dependency ->
if (dependency.name != 'unspecified') {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dependency.group)
dependencyNode.appendNode('artifactId', dependency.name)
dependencyNode.appendNode('version', dependency.version)
}
}
}
}
//publish to filesystem repo
repositories{
maven {
url "$buildDir/repo"
}
}
}
Run from terminal
./gradlew clean
./gradlew build
./gradlew --console=verbose publishToMavenLocal
The aar and pom files have been created at $HOME/.m2/repository/
How to load the library from a different project
Modify the projects's build.gradle in the following way:
allprojects {
repositories {
maven {
url "/Users/username/.m2/repository/"
}
google()
jcenter()
}
You can use $rootDir and set a relative path.
Add the library as a dependency in your app module build.gradle
implementation 'com.domain:name:1.0.0'
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)
}
}