I am working on an Android SDK made of multiple library modules and a test app module:
mySDK
|-test-app
|-lib-core
|-lib-ui
|-...
I would like to publish it on a Maven repository, with all library modules embedded (but not the test-app).
I know how to publish a single library module using Maven Publish Plugin but can't figure out how to make a Maven publication containing multiple library modules.
How would you do that ?
Just upload each module as a standalone module.
It is not mandatory to upload all the modules at the same time, the dependencies are just described in the pom file.
It can be useful putting a base script in a single gradle file with some common settings and properties (you can read them from a gradle.properties file), something like:
rootFolder/maven_push.gradle:
apply plugin: 'maven'
//....
pom.artifactId = POM_ARTIFACT_ID
pom.project {
name POM_NAME
packaging POM_PACKAGING
description POM_DESCRIPTION
url POM_URL
//...
}
//...
and then in each module/build.gradle file add:
apply from: '../maven_push.gradle'
Each module is a library by itself, so configure each one of them (besides the app) to be packaged as AAR files and deployed to the desired repo. If you are going to use the Maven publish plugin, just apply the steps to each module(to the module's build.gradle files). A good practice is to centralize the groupId and version values, perhaps in the gradle.properties file, or in the main gradle file. Same procedure applies to other plugins, like the android-gradle-maven plugin.
Related
My Android project contains a library that is shipped as AAR file.
There are multiple options to include local AAR files.
I can declare a file dependency:
implementation files('libs/mylib.aar')
Or I can put the AAR into another module and then use a project dependency:
implementation project(':mylibmodule')
However, I want to specify the exact version of my library:
mylib:1.0.0
Unfortunately, I do not know how to specify the version without using some remote repository.
Note that I do not want to upload the library to JitPack, MavenCentral or similar.
All I want is to specify the version of a local AAR file.
Update
The AAR file is a Zip-File with the following content:
/proguard.txt
/R.txt
/AndroidManifest.xml
/public.txt
/classes.jar
/res/values/values.xml
Note that the AndroidManifest.xml contains the version of the library.
However, I assume that gradle always expects a pom file for the versioning information.
I realized that gradle allows to specify a local Maven repository at a specific path:
repositories {
maven {
url uri("${projectDir}/mylibdir")
}
}
To use a local Maven repository, I need to build my library as a Maven artifact. To create a Maven artifact, it suffices to create a POM file in the right subfolder.
The AAR file remains unchanged since Maven does not care about the artifact format.
Creating a Maven artifact can be automated with the maven-publish plugin, e.g.:
apply plugin: 'maven-publish'
publishing {
publications {
myRelease(MavenPublication) {
groupId 'com.foo'
artifactId 'my-artifact'
version '1.0.0'
artifact("$buildDir/outputs/aar/my-artifact.aar")
}
}
repositories {
maven {
url "$buildDir/repo"
}
}
}
However, since I do not really need to use Maven, the simpler choice is to add the version to the AAR file name.
I did this with the following snippet in the build.gradle of my library:
android.libraryVariants.all { variant ->
variant.outputs.all {
outputFileName = "${archivesBaseName}-${variant.name}-${defaultConfig.versionName}.aar"
}
}
I have a project that have the following structure:
projectRoot
build.gradle
module1/
build.gradle
artifact1.aar
module2/
....
My artifact1.aar is a compiled artifact and i have no access to the sources.
my module 1 gradle build file is the following:
configurations.maybeCreate("default")
artifacts.add("default", file('artifact1.aar'))
With this the code contains in the .aar is available in module 2 by simply reference a gradle project dependency.
But i want to publish the .aar in my maven local, in order that it can be accessible for other android project.
I check the maven-publish plugin and the android-maven-publish plugin but the two seems to be called after java-library plugin or com.android.library plugin.
So my question is how to publish in my maven local repository an existing aar with gradle ?
I'm using gradle in version 4.8.
I used an rxbinding aar for this example.
As you correctly mentioned, there has to be a subproject in the "publisher" project, which must contain the aar, and a build file with the following content:
// rxbinding/build.gradle
apply plugin: "maven-publish"
configurations.maybeCreate("default")
def publishArtifact = artifacts.add("default", file('rxbinding-2.1.1.aar'))
publishing {
publications {
aar(MavenPublication) {
groupId = 'my.sample.artifact'
artifactId = 'somerandomname'
version = '1.0.0'
artifact publishArtifact
}
}
}
You can apply the maven-publish plugin to any project, but then you have to define the artifacts manually, like we've just done here. Some plugins (like the java-library plugin) are integrated with the maven-publish plugin to automatically publish the default artifacts of the project.
Now run ./gradlew rxbinding:publishToMavenLocal - This should place the artifact into your local repo
Add implementation 'my.sample.artifact:somerandomname:1.0.0' to the consumer app, in any project on your machine.
It is very important to mention any aar published this way, will not bring it's dependencies, so you have to know what libs are needed to actually use the published aar.
I have also created an example project, where you can try this.
If you have maven installed, you could use the install-file goal of the maven-install-plugin.
I have some code I'd like to use across multiple different projects. Let's say it's some e-commerce code that handles things like payments and shopping carts.
It seems inefficient and dangerous to copy-paste everything across different projects. And if I add one feature or fix one bug in the core e-commerce module, I'd like that change to be reflected in other projects using it too.
I would also like to re-use some of the Activities, Fragments, Adapters too.
What is a good approach to this?
When we have a library project that needs to be shared to every project on a local computer, we can make use of Maven.
A. Here the step in your library that we will you for the project:
Make a library project from Android Studio.
Add Gradle Android Maven plugin to root build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
}
}
Add apply plugin for step 1 in your library build.gradle. (NOT root build.gradle):
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
Add the following after the apply plugin, this line to determine your library when adding to project:
group = 'com.yourpackage.yourlibrary'
version = '1.0'
Add the following code in your settings.gradle:
rootProject.name = 'yourlibrary'
Then publish it to your local maven with:
./gradlew install
Or you can use gradle option in Android Studio.
Your library will be installed in $HOME/.m2/repository. Remember that to use the library you need to add like this:
Groupid:artifactid:versionid
Artifactid will be package name of your library.
B. Here the step in your Project which using the library:
Add the following code in your root build.gradle:
mavenLocal() // for local maven.
This for getting the local library maven that we have installed in step A
Then in your app project.gradle, add compile for the library:
compile 'com.yourpackage.yourlibrary:yourlibrary:1.0'
Read more:
Gradle: How to publish a Android library to local repository
https://github.com/dcendents/android-maven-gradle-plugin
https://inthecheesefactory.com/blog/how-to-upload-library-to-jcenter-maven-central-as-dependency/en
From my Knowledge 1. As others said try creating your own Module or Library and use it where ever you need 2.Use Version Control Tools Like Git(If your code changes it will be refleted in your git account)
I created a Android Library Module with Android Studio and I was able to use it in the apps and right now I need to use it for my other apps. So I was thinking about using the remote dependecies like Picasso https://github.com/square/picasso
compile 'com.squareup.picasso:picasso:2.5.2'
And I would like to know what are the steps I need to take? I read few article and website. It is very confusing.
To make your library available as a remote dependency there are only three steps you have to take:
Build your library and provide the necessary repository meta data
Put your library with meta data in a repository
Tell your project to look in that repository for dependencies
After that is in place you can have remote dependencies like this in your app's build.gradle file:
compile 'com.example.developer:lib-util:1.0.0'
This will look in all the repositories that you have registered for a group or organization called 'com.example.developer', and then an artifact named 'lib-util' with version '1.0.0'.
Build your library and provide the necessary repository meta data
That may sound complex but it's really not that hard. It's just a directory structure that looks a little like this:
com
|-- example
|-- developer
|-- lib-util
|-- 1.0.0
| |-- lib-util-1.0.0.aar
| |-- lib-util-1.0.0.aar.md5
| |-- lib-util-1.0.0.pom
| |-- lib-util-1.0.0.pom.md5
|-- maven-metadata.xml
|-- maven-metadata.xml.md5
The file lib-util-1.0.0.aar is the compiled library (in Android Archive format). The lib-util-1.0.0.pom file contains information about the library itself, such as the authors and its dependencies. The maven-metadata.xml file contains the necessary information to know which versions are available (in this case just one). And lastly the *.md5 files contain a checksum to verify file integrities. (There are also *.sha1 checksum files that I've left out for brevity.)
To build this structure you can make use of the Maven Gradle plugin. Put it in your library's build.gradle and configure the mavenDeployer properties:
library build.gradle:
apply plugin: 'com.android.library'
apply plugin: 'maven'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
uploadArchives {
repositories.mavenDeployer {
pom.groupId = 'com.example.developer'
pom.artifactId = 'lib-util'
pom.version = android.defaultConfig.versionName
// Add other pom properties here if you want (developer details / licenses)
repository(url: "file:./releases/")
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.0.1'
}
The above example is a stock library build.gradle as Android Studio 1.4 produces it for a new library but with the Maven Gradle plugin added and configured.
The second line: apply plugin: 'maven', adds the plugin. The uploadArchives closure configures it.
pom.groupId is the name of the organization/group. This will be written in the .pom file but is primarily used to actually find your library as a remote dependency.
pom.artifactId is the name of your library. Again, this will be put in the .pom file but is used to actually find your lib.
pom.version is the version of your library. You will have to increase this when you make a new release. Also put in the .pom and used to locate your lib.
The line repository(url: "file:./releases/") configures the plugin to write the structure to a filesystem directory relative to the project root.
If you run the following Gradle command in the root directory of your project you should see the Maven directory structure being built.
./gradlew clean uploadArchives
This will first clean your build and then build and perform the uploadArchives task which will create the releases directory.
Put your library with meta data in a repository
You already have a local Maven repository right now, namely on your local filesystem in your lib-util's project directory.
To make it an online remote Maven repository it only has to be reachable by http (or https) get-requests. If you have a server with a webserver like Apache or Nginx or IIS you can configure that to host the files. Or you can check them into your Github account and let that host it. You could even copy those files to Dropbox and use it to host them.
If you want to have it publicly available over Maven Central or JCenter you will have to go to their websites and register for an account where you claim your 'groupId' and you can then use their systems to upload the files so they will be hosted by them.
Tell your project to look in that repository for dependencies
By default Android Studio registers your project to look for dependencies in JCenter. Previously it used to default to Maven Central. So if you have actually uploaded your library to those repositories you wont have to do anything as it will already work.
Suppose you want to configure your project to look for remote dependencies on your local filesystem in /Users/rob/projects/lib-util/releases, and in a self-hosted Maven repository at http://developer.example.com/repo/. Add those repository urls to your project's build.gradle (so not in your library's):
project build.gradle:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
maven { url '/Users/rob/projects/lib-util/releases/' }
maven { url 'http://developer.example.com/repo/' }
jcenter()
}
}
The example above is the stock project build.gradle as Android Studio provides it with just two extra repositories. Looking dependencies up goes in the order listed. So in this case it first checks the local filesystem, then the self-hosted repo and finally it looks in JCenter.
I'm currently developing both a library (with no activities) and an application that depends on the library. Currently, I have these as separate projects, and I can copy the generated .aar file from the library project into the application project's libs folder, and re-sync gradle. However, this is an inefficient process because I have to rebuild and manually re-copy the .aar file every time I make a change to the library project. My question is, how can I streamline this process so that my application automatically uses the library's most recently generated .aar file?
1) In your app's settings.gradle include your lib as a project:
include ':lib-project'
project(':lib-project').projectDir = new File('../path/to/lib/project/lib-project')
The path to your lib project is relative to the settings.gradle location on your filesystem
2) in your app's build.gradle add lib project as a dependency:
dependencies {
compile project(':lib-project')
...
}
how can I streamline this process so that my application automatically uses the library's most recently generated .aar file?
Option #1: Dedicated Library
Step #1: Put your app project and the library project as children of a common root directory for the overall project. For the purposes of this answer, I'll call these app/ and library/, respectively.
Step #2: In the top level (i.e., the common root directory), have a settings.gradle file that lists these modules:
include ':app', ':library'
Step #3: In the top level, have a build.gradle file that sets up the Gradle for Android plugin and any other common stuff of interest, such as:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
(note that the above file is what you get from a native Android Studio project, created by the IDE)
Step #3: In the library/ directory, have a build.gradle file that uses the com.android.library plugin
Step #4: In the app/ directory, have a build.gradle file that has compile project(':library') in its dependencies to pull in the library
It may be that your AAR is the deliverable, not the app (e.g., the library is an open source one for community use, and the app is a demo app). In that case, you might use debugCompile in app/ to pull in the local library project for debug builds, but have releaseCompile to pull in the AAR from a published source, to confirm that you can build from the same thing that users of the AAR use.
Most of my CWAC libraries are set up this way (e.g., cwac-richedit).
Option #2: Publish the AAR Locally
You can use the maven plugin and the uploadArchives task to upload to a local Maven-style repo:
apply plugin: 'maven'
uploadArchives {
repositories.mavenDeployer {
pom.groupId = PUBLISH_GROUP_ID
pom.artifactId = PUBLISH_ARTIFACT_ID
pom.version = PUBLISH_VERSION
repository(url: LOCAL_REPO)
}
}
Here, my constants are pulled in from a gradle.properties file, and LOCAL_REPO is a file:/// URL pointing to a local repo. You can then run gradle uploadArchives to generate the AAR and push it to the local repo.
Then, your app can have a maven { url LOCAL_REPO } closure in the repositories closure, and can pull in the AAR artifact from there as if it was coming from a public repo (e.g., Maven Central).
My CWAC libraries use the uploadArchives task, but only for publishing to my local mirror of my Amazon S3-hosted Maven repo.
This approach would be if you really wanted to work off of the AAR, but wanted to do so from multiple projects. Note that you can certainly publish this to some other sort of Maven repo (e.g., a Sonatype server) for enterprise use.
Option #3: Mod a Module to Point to the Library Elsewhere
This is Pavel Dudka's approach in his answer. I haven't tried this. Off the cuff, this would be a good approach if you want to depend upon the library from multiple apps, but you're not really concerned about having an actual AAR as a thing to distribute around.
And I'm sure there are other options than these three.