Sharing uploadArchives task across modules - android

I'm working on a repo with a set of releasable libraries each in a module. The idea is each library should be able to be released individually with i.e., ./gradlew upload.
Currently in each module I have the following code to publish it:
uploadArchives {
repositories {
mavenDeployer {
repository(url: "<url>") {
authentication(userName: System.getenv('USER_NAME'), password: System.getenv('PASSWORD'))
pom.groupId = "$groupId"
pom.artifactId = "$artifactId"
pom.version = android.defaultConfig.versionName
}
}
}
}
afterEvaluate {
publishing {
publications {
library(MavenPublication) {
setGroupId "$groupId"
setArtifactId "$artifactId"
version android.defaultConfig.versionName
artifact bundleReleaseAar
}
}
}
}
I'd love to have a way to share those gradle tasks and to avoid repeating them in each module but haven't found a way to do that. One tricky thing probably is that artifactId would be different in each module so assuming I could extract those gradle tasks there should be a way to set artifactId individually.
Can someone shed me some light? Thanks

You can put all of your code into a simple build.gradle and use apply from: to apply to multiple build.gradle files.
For instance, I have this compile.gradle script that I use in many places: kotlin/build.gradle and java/build.gradle.
Instead of writing your own "publishing" build.gradle, I would suggest you a popular script that is open source and readily available, gradle-mvn-push.gradle.
Here is an example setup for your project:
root
|
| gradle
| --- gradle-mvn-mpp-push.gradle
|
| - module a
| --- build.gradle - apply from: rootProject.file("gradle/gradle-mvn-mpp-push.gradle")
|
| - module b
| --- build.gradle - apply from: rootProject.file("gradle/gradle-mvn-mpp-push.gradle")
|
See the docs here: https://docs.gradle.org/current/userguide/plugins.html#sec:script_plugins

Related

How do I publish an AAR to Maven Local With JavaDocs

I need to publish my android library (aar) using Gradle to Maven local repo.
But the publication script needs to also generate the Javadocs, while ONLY including Public and Protected methods and classes.
Can't seem to find any information online, especially about the Javadocs part...
Help, I never published a library before.
Ok, after much research I found a solution, so I'm going to share it here if anyone will need this. (I don't want you to be frustrated like I was).
1) Create an android library as a new module inside your project.
2) Inside the build gradle of your library place this code:
plugins {
id 'com.android.library'
id 'maven-publish'
}
android {
nothing special here...
}
This is the code for creating the Javadocs(still inside build.gradle):
task androidJavadocs(type: Javadoc){
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
android.libraryVariants.all{ variant->
if (variant.name == 'release'){
owner.classpath += variant.javaCompileProvider.get().classpath
}
}
// excluding a specific class from being documented
exclude '**/NameOfClassToExclude.java'
title = null
options{
doclet = "com.google.doclava.Doclava"
docletpath = [file("libs/doclava-1.0.6.jar")]
noTimestamp = false
// show only Protected & Public
memberLevel = JavadocMemberLevel.PROTECTED
}
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs){
archiveClassifier.set('javadoc')
from androidJavadocs.destinationDir
}
task androidSourcesJar(type: Jar){
archiveClassifier.set('sources')
from android.sourceSets.main.java.srcDirs
}
This is to publish the library to MavenLocal(still inside build.gradle):
afterEvaluate {
publishing{
publications{
release(MavenPublication){
groupId = "com.example.mylibrary"
artifactId = "mycoollibrary"
version = "1.0"
// Applies the component for the release build variant
from components.release
// Adds javadocs and sources as separate jars.
artifact androidSourcesJar
artifact androidJavadocsJar
}
}
}
}
Your default dependencies block:
dependencies {
your dependencies...
}
3) Now you can download the doclava doclet:
Extract the zip, copy the doclava-1.0.6.jar and paste it into your LibraryName/libs folder (can be found using the project view).
You only need doclava if you want to be able to use #hide.
With this annotation, you can exclude specific methods from your Javadocs.
4) Build and publish your library:
Find the gradle tab at the top right side of android studio, or find it from the toolbar View->Tool Windows->Gradle.
Now find your library -> tasks -> publishing -> publishReleasePublicationToMavenLocal.
5) To consume the library from another project:
Go to the settings.gradle file (of the consuming project) and add MavenLocal() as the first repository in the the dependencyResolutionManagement block.
And inside the module build gradle add your library as a dependency:
dependencies{
implementation 'com.example.mylibrary:mycoollibrary:1.0'
}

How to add if condition in build.gradle? [duplicate]

I have a multi-flavored, multi-build-typed android project and I want to integrate the NewRelic plugin. But I have to apply it only for one of the customers, thus only for one product flavor.
NewRelic uses instrumentation and the plugin would generate code in other flavors if I applied the plugin there, and that is not permitted for us.
So my question is: How can I use the apply plugin: something command in the gradle file to be applied to only one of my flavors?
Use this code:
if (!getGradle().getStartParameter().getTaskRequests()
.toString().contains("Develop")){
apply plugin: 'com.google.gms.google-services'
}
getGradle().getStartParameter().getTaskRequests().toString() returns something like [DefaultTaskExecutionRequest{args=[:app:generateDevelopDebugSources],projectPath='null'}] so as stated in the comments Develop must start with an uppercase.
Tried different solutions, but none of them worked for me. This is what I came up with and seems to work as far as I tested:
build.gradle
productFlavors {
someFlavorWithGoogleGcm {
dimension "type"
applicationId "com.example.withGcm"
ext.useGoogleGcm = true
}
someFlavorWithoutGoogleGcm {
dimension "type"
applicationId "com.example.withoutGcm"
}
}
And outside the configuration, inside the build.gradle file:
android.productFlavors.each { flavor ->
if (getGradle().getStartParameter().getTaskRequests().toString().toLowerCase().contains(flavor.name) && flavor.ext.useGoogleGcm) {
println("Building flavor with Google GCM [${flavor.name}] - applying plugin")
apply plugin: 'com.google.gms.google-services'
}
}
I simply used apply plugin: 'com.google.gms.google-services' inside the flavor in app level build.gradle and it works just fine.
productFlavors {
..... your other flavors ....
yourFlv {
....
....
apply plugin: 'com.google.gms.google-services'
}
}
No extra step needed.
Define variable - def fl
Initialize variable in you Flavours (and/or builds)
productFlavors {
freeFlavour {
(...)
fl = "free"
}
paidFlavour {
(...)
fl = "paid"
}
}
Use if statement -
if (fl == "free") {
apply plugin: something
}
I found a solution, but it is not the best so far.
So I'm not sure anymore, that what I wanted to do initially is possible.
The gradle file evaluation and the choosing of the right flavor and build type is in different phases of the gradle build, so what I've done is:
I use a build parameter from the command line. When that paramerer is true, I apply the plugin, when it is not even there, I also apply it (for IDE build).
I use Jenkins, so I could write that parameter in the build job.
build.gradle file:
// First we have to attach a task to the project, which will be running first
gradle.projectsEvaluated {
preBuild.dependsOn(applyNewRelicByProperty)
}
// Then check on the parameter, which comes from the command line
task applyNewRelicByProperty {
if(!project.hasProperty('compileNewRelic')) {
// NewRelic on: 'compileNewRelic' property not set, so running from IDE.
apply plugin: 'newrelic'
} else if(project.hasProperty('compileNewRelic') && project.getProperties().get('compileNewRelic').equals('true')) {
// NewRelic on: 'compileNewRelic' property is set and it is 'true'.
apply plugin: 'newrelic'
} else {
// NewRelic off
println("No NewRelic")
}
}
And you have to run the gradle build by this:
assembleYourApp -PcompileNewRelic=true
After upgrading to Gradle 4.2, the approach by Tarps stopped working, so I ended up combining it with Erik's answer.
Set ext.useGoogleGcm for each flavour in your build.gradle:
productFlavors {
a {
...
ext.useGoogleGcm = true
}
b {
...
ext.useGoogleGcm = false
}
}
Then at the bottom of the file:
apply plugin: 'com.google.gms.google-services'
afterEvaluate {
android.productFlavors.each { flavor ->
tasks.matching {
it.name.contains('GoogleServices') && it.name.contains(flavor.name.capitalize())
}*.enabled = flavor.ext.useGoogleGcm
}
}
In the output for your assembleRelease task, you should see tasks with "GoogleServices" in the name have run for those that are true and skipped for those that are false. If your build complains about toCapitalize, you could use toLowerCase on both it.name and flavor.name.
In the case of the Google Services Gradle plugin, the following works.
apply plugin: 'com.google.gms.google-services'
afterEvaluate {
tasks.matching { it.name.contains("GoogleServices") && !it.name.contains(yourFlavorName) }*.enabled = false
}
where yourFlavorName is a capitalised string containing the name of your flavor that must apply the plugin; all other flavors don't use the plugin.
Note that the plugin is still applied to other flavors; this solution just disables the *GoogleServices* task(s) for them. That assumes that the Google Services Gradle plugin only applies changes by adding a task containing substring "GoogleServices", which might not work in the future.
To check that this works, you can check the dependencies, e.g. like so:
./gradlew app:dependencyInsight --configuration yourFlavorNameDebugCompileClasspath --dependency google | grep -i services
That should show some dependencies for yourFlavorName but not for other flavor names:
./gradlew app:dependencyInsight --configuration otherFlavorNameDebugCompileClasspath --dependency google | grep -i services

Upload archive for a library with flavors with gradle

I'm developing an SDK with multiple libraries and an example app to show how to use it. The libraries are uploaded in a local maven repo that the app uses to import them.
Everything works fine until I try to use different flavors for one of the libraries (and for the app).
When I have flavors, the uploadArchive task does not show any error but the library is not uploaded. All the other libraries are uploaded successfully.
I have found this: https://discuss.gradle.org/t/pom-files-for-multi-flavored-android-lib-not-published-on-uploadarchives-task/898
It is an old post but it does not have any answer.
Is it possible to upload one of the flavors of a library?
This is my archive.gradle file:
apply plugin: 'maven'
apply from: "../maven-repo.gradle"
uploadArchives {
repositories {
mavenDeployer {
def folder = "file://localhost" + myMavenRepoDir()
repository(url: folder)
pom.groupId = GROUP
pom.artifactId = POM_ARTIFACT_ID
pom.version = VERSION_NAME
pom.project {
name POM_NAME
packaging POM_PACKAGING
description POM_DESCRIPTION
}
}
}
}

Android - multiple AAR variant Nexus upload

I have a project with a structure like below. It has a 'main-module' that is the focus of our development, which should be able to publish AARs for two variants (debug, release) to Nexus. We also have a bunch of other dependency modules and a test app.
project
|
|- app
|- main-module
|- module-a
|- module-b
...
I'm looking to run a build that will package the main-module AARs an then upload both of these to Nexus repos. The debug AAR will go to a snapshots repo, and the release version will go to a release repo. I have some puzzle pieces but I'm not quite sure how to tie it together.
What I have:
Build AARs
gradlew assemble
Publish an AAR
project.uploadArchives {
repositories {
mavenDeployer {
repository(url: "http://localhost:8081/nexus/content/repositories/snapshots/") {
authentication(userName: "deployment", password: "password123")
}
pom.version = "0.0.1-SNAPSHOT"
pom.artifactId = "MainModule"
pom.groupId = "com.myorg.test"
}
}
The build works and I can push a version to Nexus. I don't know how to provide config for the debug and release versions so they have the correct repository (e.g. /snapshots vs /release) and the correct version (release version name won't contain SNAPSHOT).
Once working I'll move the names, versions and credentials out to properties, with the credentials not checked in to source control before someone points that out.
Using:
gradle-wrapper 4.4
gradle plugin 3.1.4
So after several days of digging around I found the solution. This is pretty rough, I haven't optimised it yet, but the solution works. Note it assumes your aar files contain the text 'debug' and 'release' in the name, if they don't then you can adjust to your project. I wouldn't know how this applies to modules that have more than just the debug and release variants, or if product flavours are involved.
android-maven-gradle-plugin
Integrate the android-maven-gradle-plugin. Steps are in the documentation link.
Module build.gradle
apply plugin: 'com.github.dcendents.android-maven'
afterEvaluate {
uploadArchives {
repositories {
mavenDeployer {
addFilter('debug') { artifact, file ->
artifact.name.contains("debug")
}
addFilter('release') { artifact, file ->
artifact.name.contains("release")
}
pom('debug').groupId = 'com.yourgroup'
pom('release').groupId = 'com.yourgroup'
pom('debug').artifactId = "MyArtifact"
pom('release').artifactId = "MyArtifact"
pom('debug').version = android.defaultConfig.versionName + "-SNAPSHOT"
pom('release').version = android.defaultConfig.versionName
pom.packaging = 'aar'
repository(url: "http://localhost:8081/nexus/content/repositories/releases/") {
authentication(userName: 'user'), password: 'pwd')
}
snapshotRepository(url: "http://localhost:8081/nexus/content/repositories/snapshots/") {
authentication(userName: 'user'), password: 'pwd')
}
}
}
}
}

Android Library - Publish Multiple Variants to Local Maven Repository using Gradle

I am using Android Gradle plugin 0.13.2, Android Studio 0.8.11, Gradle 2.1 and maven plugin.
I would like to install multiple variants (flavour + build type) of my Android Library to local Maven repository all with one command (task).
Currently Android Gradle plugin 0.13.2 allows me to set publishNonDefault flag to publishing all variants, but as the documentation states it will publish the variants with a classifier which is not compatible with Maven Repository.
My workaround right now is to use defaultPublishConfig "myVariant" and change it for every variant I have.
apply plugin: 'com.android.library'
apply plugin: 'maven'
android {
defaultPublishConfig "myVariant"
.
.
.
}
task installArchives(type: Upload) {
repositories.mavenInstaller {
configuration = configurations.getByName(Dependency.DEFAULT_CONFIGURATION)
pom.groupId = "com.company"
pom.artifactId = "mylibrary"
pom.version = "1.0.0-myVariant"
}
}
I would like to have a single task that would properly publish all variants to local Maven repository.
To solve this I had to create one Upload task for each variant and make them depend on each other and on a master task that starts the process.
apply plugin: 'com.android.library'
apply plugin: 'maven'
android {
.
.
.
}
// Master task that will publish all variants
def DefaultTask masterTask = project.tasks.create("installArchives", DefaultTask)
android.libraryVariants.all { variant ->
variant.outputs.each { output ->
// Configuration defines which artifacts will be published, create one configuration for each variant output (artifact)
def Configuration variantConfiguration = project.configurations.create("${variant.name}Archives")
project.artifacts.add(variantConfiguration.name, output.packageLibrary)
// Create one Upload type task for each configuration
def Upload variantTask = project.tasks.create("${variant.name}Install", Upload)
variantTask.configuration = variantConfiguration
variantTask.repositories.mavenInstaller {
pom.groupId = "com.yourcompany"
pom.artifactId = "yourLibrary"
pom.version = "1.0.0-${variant.name}" //Give a different version for each variant
pom.packaging = "aar"
}
// Make all tasks depend on each other and on master task
masterTask.dependsOn variantTask
masterTask = variantTask
}
}
The task installArchives will publish all variants to the local Maven repository.
./gradlew installArchives

Categories

Resources