I'm working on properly setting up my Gradle scripts for publishing an .aar directly to Maven Central (with JFrog sunsetting Bintray, numerous resources about publishing to Bintray are no longer relevant). One of the prerequisites is to have all artifacts (aar, sources jar, java-doc jar, pom.xml) uploaded alongside corresponding GPG-signature files (e.g. sources.jar.asc).
Following these two guides (which are very much alike), I've largely managed to do so:
https://medium.com/#nmauti/sign-and-publish-on-maven-central-a-project-with-the-new-maven-publish-gradle-plugin-22a72a4bfd4b
https://www.albertgao.xyz/2018/01/18/how-to-publish-artifact-to-maven-central-via-gradle/
However, though well describing the solution using Gradle, both guides seem to focus on plain .jar's rather than .aar's. In particular, I wasn't sure about what to set up as a project archive in order to put on the automated sign+publish list, as suggested:
project.artifacts {
archives sourceJar // Ok, I have a sourceJar task - will be signed and uploaded
archives javadocJar // I use Dokka, but got that to work by registering my dokka task
archives jar // What's "jar"? this doesn't help much!... :-/
}
I even tried registering the output .aar file, explicitly:
publications {
android.libraryVariants.all { variant ->
if (shouldPublishVariant(variant)) {
// ...
// ...
variant.outputs.forEach { output ->
project.artifacts {
archives output.outputFile // The full path of the .aar to publish!
}
}
}
}
}
But that seemed to have resulted in this flaky error:
Execution failed for task ':detox:publishMavenFullReleaseAarPublicationToMavenRepository'.
> Failed to publish publication 'mavenFullReleaseAar' to repository 'maven'
> Invalid publication 'mavenFullReleaseAar': artifact file does not exist: '.../build/outputs/aar/library-full-release.aar.asc'
I'm looking for a stable, bullet-proof solution that would sort this out end-to-end, with no flaky errors.
As a solution, I've found that registering the task generating the .aar as a project archive -- rather than registering the file itself, does the trick (much like as done for the sources and javadoc jars):
publications {
android.libraryVariants.all { variant ->
if (shouldPublishVariant(variant)) {
// ...
// ...
variant.outputs.forEach { output ->
project.artifacts {
// For example: bundleProdReleaseAar is the task that generates library-prod-release.aar
archives project.tasks["bundle${variant.name.capitalize()}Aar"]
}
}
}
}
}
Related
I want to upload NDK symbols on every build i do,
Under my Android inside gradle i use to have:
applicationVariants.all { variant ->
def variantName = variant.name.capitalize()
println("symbols will be added on varinat ${variantName}")
def task = project.task("ndkBuild${variantName}")
task.finalizedBy project.("uploadCrashlyticsSymbolFile${variantName}")
}
this does not compile anymore since i moved to FireBase :
Could not get unknown property 'uploadCrashlyticsSymbolFile
I don't see this task running.
I basiclly need this task to run on every build:
./gradlew app:assembleBUILD_VARIANT\
app:uploadCrashlyticsSymbolFileBUILD_VARIANT
Add this at the bottom of app's build.gradle outside android { ... } block.
afterEvaluate {
android.applicationVariants.all { variant ->
def variantName = variant.name.capitalize()
println("symbols will be added on variant ${variantName}")
def task = tasks.findByName("assemble${variantName}")
def uploader = "uploadCrashlyticsSymbolFile${variantName}"
// This triggers after task completion
task?.finalizedBy(uploader)
// This ensures ordering
task?.mustRunAfter(uploader)
}
}
You can try without afterEvaluate block. It should still work.
Likely you'd need to use Firebase App Distribution, which permits automatic upload of release build artifacts - and if you have the artifact with the matching debug symbols, they could actually be used - without the matching assembly, the symbols are somewhat irrelevant.
Number 1 is obviously a wrongful assumption, because the documentation clearly states:
./gradlew app:assembleBUILD_VARIANT app:uploadCrashlyticsSymbolFileBUILD_VARIANT
And this is already answered here.
In order to always upload, one can create a task dependency:
assembleRelease.finalizedBy uploadCrashlyticsSymbolFileRelease
This may require setting unstrippedNativeLibsDir and strippedNativeLibsDir.
Hi, I would like to create a job in Jenkins where I would like to build one apk from 2 Android repositories.
I tried it with both Jenkinsfile and Gradle wrapper in the Jenkins GUI, but both are giving the same error at the same point, at the verification Gradle commands.
Since the code in the first repository is depending on the code from the 2nd, the structure was designed that they have to be sibling directories to reach each other.
What went wrong:
Could not determine the dependencies of task ':app:testStaging_gakUnitTest'.
Could not resolve all task dependencies for configuration ':app:staging_gakUnitTestRuntimeClasspath'.
Could not resolve project :ticketingcommons.
Required by:
project :app
Unable to find a matching variant of project :ticketingcommons:
First one is a specific application code repository.
Second one contains the commons for the specific apps to run tests, validation etc...
In the configuration I only set the source-code management and building process fields so far.
I have been trying with pipelines, freestyle projects, multibranch pipelines and nothing seemed to be working.
In the Jenkinsfile, I have the following code, which is supposed to do the same I was doing from the Jenkins GUI:
pipeline {
agent {
// Run on a build agent where we have the Android SDK installed
label 'master'
}
options {
// Stop the build early in case of compile or test failures
skipStagesAfterUnstable()
}
stages {
stage('Compile') {
steps {
// Compile the app and its dependencies
sh 'chmod +x gradlew'
sh './gradlew compileDebugSources'
}
}
stage('Unit test') {
steps {
// Compile and run the unit tests for the app and its dependencies
sh './gradlew test'
// Analyse the test results and update the build result as appropriate
junit 'app/build/test-results/**/*.xml'
}
}
stage('Build APK') {
steps {
// Finish building and packaging the APK
sh './gradlew assembleDev'
// Archive the APKs so that they can be downloaded from Jenkins
archiveArtifacts '**/*.apk'
}
}
stage('Stage Archive') {
steps {
//tell Jenkins to archive the apks
archiveArtifacts artifacts: 'app/build/outputs/apk/*.apk', fingerprint: true
}
}
stage('Static analysis') {
steps {
// Run Lint and analyse the results
sh './gradlew lintDebug'
androidLint pattern: '**/lint-results-*.xml'
}
}
}
post {
failure {
// Notify developer team of the failure
mail to: 'mymail#whynotworking.com', subject: 'Oops!', body: "Build ${env.BUILD_NUMBER} failed; ${env.BUILD_URL}"
}
}
}
I don't know how to make Jenkins have them as sibling directories after cloning them, so the app can see the commons and run the commands. Now it is failing at the tests, but every validation Gradle command makes it fail.
A simple solution could be to create two jobs and customize their workspace directory (So you can use the same directory for both jobs). In your first job just load the repository from git and in the second load the repository and run whatever commands you want.
I am trying to publish the library to JCenter with Bintray, according to this article: https://medium.com/#anitaa_1990/6-easy-steps-to-upload-your-android-library-to-bintray-jcenter-59e6030c8890.
I successfully added the library to Bintray, but when I click on "Add to JCenter" button and send compose message - I am getting an error:
Failed to send a message: Package should include sources as part of the package.
Please, tell me what am I doing wrong?
Your Bintray Maven Package doesn't contain the sources, only .aar and the .pom. The in the blog post isn't linked to JCenter, see blog's package here.
Bintray's wiki states that you have to include the sources.
I would use this blog post or this one, where the packages are actually linked to JCenter.
For developers who reach here today, make sure your configuration file has artifact(sourcesJar.get()) in publishing{} like these lines below (not complete build.gradle.kts).
val sourcesJar by tasks.registering(Jar::class) {
classifier = "sources"
from(sourceSets.main.get().allSource)
}
publishing {
publications {
create<MavenPublication>("default") {
from(components["java"])
artifact(dokkaJar)
}
}
publications.invoke {
publicationName(MavenPublication::class) {
artifactId = artifactID
artifact(sourcesJar.get()) // This line
}
}
}
I'm using Android Studio and desperately trying to get gradle to publish both my debug & release aar's to artifactory with separate repoKeys. Preferably as two separate tasks. I have read this excellent guide, but I don't want to change my gradle file each time in order to deploy.
I can easily create two pom files, but have not managed to make the artifactory plugin dynamic enough to switch my two rep keys.
I feel this is the closest I've come but it's not quite there:
String art_repo = ''
artifactory {
contextUrl = 'https://www.myjfrogrepo.com'
publish {
repository {
// The Artifactory repository key to publish to
repoKey = "${art_repo}"
I have then created a custom task which sets the art_repo variable.
task debugPublishTojFrog {
group "Publishing"
art_repo = 'libs-snapshot-local'
art_publicationName = 'debugAar'
doLast {
println "Successfully published ${art_repo} to jFrog"
}
}
debugPublishTojFrog.finalizedBy artifactoryPublish
This responds with the error
Target repository cannot be empty
This leads me to think the repoKey is set at build time and not at run time because my custom task's changes seem to be ignored.
Any suggestions really would be very much appreciated.
A standard way to do this in gradle is to test for the version you are about to publish.
This is exactly what the guide you link to advocates:
repoKey = libraryVersion.endsWith('SNAPSHOT') ? 'libs-snapshot-local' : 'libs-release-local'
What is wrong with this solution?
Edit: If the problem lies with having to change gradle or the gradle.properties file, why not use properties from the command line.
repoKey = project.hasProperty('releaseVersion') ? 'libs-release-local' : 'libs-snapshot-local'
And build your snapshot with
gradle build
And build your release with
gradle build -PreleaseVersion=1.0.0-GA
You can also use this releaseVersion property at several other locations, like your software metadata, your publication information...
I have an Android Library, it's generating a debug.aar and a release.aar, I need to copy the release.aar to another folder as a reference to other part of the project.
What I've done now is in this Android Library build.gradle I defined a task:
task copyAARToCommonLibs(type: Copy) {
from('../build/outputs/aar') {
include '*-release.arr'
}
into '../SomeSampleApps/libs'
}
I'm trying to run this task after the arr is generated, which I assume is assembleRelease stage, so I tried do this in this build.gradle
assembleRelease.doLast{
copyAARToCommonLibs
}
I build the overall project using
gradle build
But this task is running at the very beginning of the whole process.
I also tried this:
applicationVariants.all { variant ->
variant.assemble.doLast {
copyAARToCommonLibs
}
}
inside android{} property(I guess that's what it's called?)
Running gradle build, got this error: Could not find property 'applicationVariants'
I then came across this snippet:
tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn copyAARToCommonLibs }
But it seems this makes the task to run after compiling, I don't know exactly how to modify this to run after assemble.
Could someone please correct me where I did wrong and how can I get this copy task work after the .arr file is generated?
It seems that finalizedBy might be helpful.
assembleRelease.finalizedBy(copyAARToCommonLibs)
Mind the fact that in the following way you won't define a dependency:
assembleRelease.doLast {
copyAARToCommonLibs
}
actually.. it does exactly nothing. You need to execute the task:
assembleRelease.doLast {
copyAARToCommonLibs.execute()
}
but running task in the following way is discouraged and very bad practice.
You can also try:
assembleRelease.doLast {
copy {
from('../build/outputs/aar') {
include '*-release.aar'
}
into '../AscendonSDKSamples/libs'
}
}
I went with finalizedBy() but had to include it within an afterEvaluate...
afterEvaluate {
if (gradle.startParameter.taskNames.contains(":app:assembleFatReleaseInternal")) {
play.enabled = true
play.commit = true
play.track = "internal"
play.releaseStatus = "completed"
play.releaseName = versionName
generateFatReleaseInternalBuildConfig.dependsOn set_build_date
assembleFatReleaseInternal.finalizedBy(uploadCrashlyticsSymbolFileFatReleaseInternal)
uploadCrashlyticsSymbolFileFatReleaseInternal.finalizedBy(publishFatReleaseInternal)
}
}
This worked well for automating the upload of native symbols to Fabric / Crashlytics and other things such as automated play store publishing.
Because android studio add task by dynamic,so assembleRelease will not be recognized.
Just add hook after task added event happens.
tasks.whenTaskAdded {
theTask ->
if (theTask.name.contains('externalNativeBuild')) {
theTask.doLast{
println "[*] begin to copy file."
}
}
// println theTask.name
}